• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2015 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "memchunk_test.h"
26 
27 #include <CUnit/CUnit.h>
28 
29 #include <nghttp2/nghttp2.h>
30 
31 #include "memchunk.h"
32 #include "util.h"
33 
34 namespace nghttp2 {
35 
test_pool_recycle(void)36 void test_pool_recycle(void) {
37   MemchunkPool pool;
38 
39   CU_ASSERT(!pool.pool);
40   CU_ASSERT(0 == pool.poolsize);
41   CU_ASSERT(nullptr == pool.freelist);
42 
43   auto m1 = pool.get();
44 
45   CU_ASSERT(m1 == pool.pool);
46   CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize);
47   CU_ASSERT(nullptr == pool.freelist);
48 
49   auto m2 = pool.get();
50 
51   CU_ASSERT(m2 == pool.pool);
52   CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize);
53   CU_ASSERT(nullptr == pool.freelist);
54   CU_ASSERT(m1 == m2->knext);
55   CU_ASSERT(nullptr == m1->knext);
56 
57   auto m3 = pool.get();
58 
59   CU_ASSERT(m3 == pool.pool);
60   CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
61   CU_ASSERT(nullptr == pool.freelist);
62 
63   pool.recycle(m3);
64 
65   CU_ASSERT(m3 == pool.pool);
66   CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
67   CU_ASSERT(m3 == pool.freelist);
68 
69   auto m4 = pool.get();
70 
71   CU_ASSERT(m3 == m4);
72   CU_ASSERT(m4 == pool.pool);
73   CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
74   CU_ASSERT(nullptr == pool.freelist);
75 
76   pool.recycle(m2);
77   pool.recycle(m1);
78 
79   CU_ASSERT(m1 == pool.freelist);
80   CU_ASSERT(m2 == m1->next);
81   CU_ASSERT(nullptr == m2->next);
82 }
83 
84 using Memchunk16 = Memchunk<16>;
85 using MemchunkPool16 = Pool<Memchunk16>;
86 using Memchunks16 = Memchunks<Memchunk16>;
87 using PeekMemchunks16 = PeekMemchunks<Memchunk16>;
88 
test_memchunks_append(void)89 void test_memchunks_append(void) {
90   MemchunkPool16 pool;
91   Memchunks16 chunks(&pool);
92 
93   chunks.append("012");
94 
95   auto m = chunks.tail;
96 
97   CU_ASSERT(3 == m->len());
98   CU_ASSERT(13 == m->left());
99 
100   chunks.append("3456789abcdef@");
101 
102   CU_ASSERT(16 == m->len());
103   CU_ASSERT(0 == m->left());
104 
105   m = chunks.tail;
106 
107   CU_ASSERT(1 == m->len());
108   CU_ASSERT(15 == m->left());
109   CU_ASSERT(17 == chunks.rleft());
110 
111   char buf[16];
112   size_t nread;
113 
114   nread = chunks.remove(buf, 8);
115 
116   CU_ASSERT(8 == nread);
117   CU_ASSERT(0 == memcmp("01234567", buf, nread));
118   CU_ASSERT(9 == chunks.rleft());
119 
120   nread = chunks.remove(buf, sizeof(buf));
121 
122   CU_ASSERT(9 == nread);
123   CU_ASSERT(0 == memcmp("89abcdef@", buf, nread));
124   CU_ASSERT(0 == chunks.rleft());
125   CU_ASSERT(nullptr == chunks.head);
126   CU_ASSERT(nullptr == chunks.tail);
127   CU_ASSERT(32 == pool.poolsize);
128 }
129 
test_memchunks_drain(void)130 void test_memchunks_drain(void) {
131   MemchunkPool16 pool;
132   Memchunks16 chunks(&pool);
133 
134   chunks.append("0123456789");
135 
136   size_t nread;
137 
138   nread = chunks.drain(3);
139 
140   CU_ASSERT(3 == nread);
141 
142   char buf[16];
143 
144   nread = chunks.remove(buf, sizeof(buf));
145 
146   CU_ASSERT(7 == nread);
147   CU_ASSERT(0 == memcmp("3456789", buf, nread));
148 }
149 
test_memchunks_riovec(void)150 void test_memchunks_riovec(void) {
151   MemchunkPool16 pool;
152   Memchunks16 chunks(&pool);
153 
154   std::array<char, 3 * 16> buf{};
155 
156   chunks.append(buf.data(), buf.size());
157 
158   std::array<struct iovec, 2> iov;
159   auto iovcnt = chunks.riovec(iov.data(), iov.size());
160 
161   auto m = chunks.head;
162 
163   CU_ASSERT(2 == iovcnt);
164   CU_ASSERT(m->buf.data() == iov[0].iov_base);
165   CU_ASSERT(m->len() == iov[0].iov_len);
166 
167   m = m->next;
168 
169   CU_ASSERT(m->buf.data() == iov[1].iov_base);
170   CU_ASSERT(m->len() == iov[1].iov_len);
171 
172   chunks.drain(2 * 16);
173 
174   iovcnt = chunks.riovec(iov.data(), iov.size());
175 
176   CU_ASSERT(1 == iovcnt);
177 
178   m = chunks.head;
179   CU_ASSERT(m->buf.data() == iov[0].iov_base);
180   CU_ASSERT(m->len() == iov[0].iov_len);
181 }
182 
test_memchunks_recycle(void)183 void test_memchunks_recycle(void) {
184   MemchunkPool16 pool;
185   {
186     Memchunks16 chunks(&pool);
187     std::array<char, 32> buf{};
188     chunks.append(buf.data(), buf.size());
189   }
190   CU_ASSERT(32 == pool.poolsize);
191   CU_ASSERT(nullptr != pool.freelist);
192 
193   auto m = pool.freelist;
194   m = m->next;
195 
196   CU_ASSERT(nullptr != m);
197   CU_ASSERT(nullptr == m->next);
198 }
199 
test_memchunks_reset(void)200 void test_memchunks_reset(void) {
201   MemchunkPool16 pool;
202   Memchunks16 chunks(&pool);
203 
204   std::array<uint8_t, 32> b{};
205 
206   chunks.append(b.data(), b.size());
207 
208   CU_ASSERT(32 == chunks.rleft());
209 
210   chunks.reset();
211 
212   CU_ASSERT(0 == chunks.rleft());
213   CU_ASSERT(nullptr == chunks.head);
214   CU_ASSERT(nullptr == chunks.tail);
215 
216   auto m = pool.freelist;
217 
218   CU_ASSERT(nullptr != m);
219   CU_ASSERT(nullptr != m->next);
220   CU_ASSERT(nullptr == m->next->next);
221 }
222 
test_peek_memchunks_append(void)223 void test_peek_memchunks_append(void) {
224   MemchunkPool16 pool;
225   PeekMemchunks16 pchunks(&pool);
226 
227   std::array<uint8_t, 32> b{
228       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
229       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
230   },
231       d;
232 
233   pchunks.append(b.data(), b.size());
234 
235   CU_ASSERT(32 == pchunks.rleft());
236   CU_ASSERT(32 == pchunks.rleft_buffered());
237 
238   CU_ASSERT(0 == pchunks.remove(nullptr, 0));
239 
240   CU_ASSERT(32 == pchunks.rleft());
241   CU_ASSERT(32 == pchunks.rleft_buffered());
242 
243   CU_ASSERT(12 == pchunks.remove(d.data(), 12));
244 
245   CU_ASSERT(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d)));
246 
247   CU_ASSERT(20 == pchunks.rleft());
248   CU_ASSERT(32 == pchunks.rleft_buffered());
249 
250   CU_ASSERT(20 == pchunks.remove(d.data(), d.size()));
251 
252   CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
253 
254   CU_ASSERT(0 == pchunks.rleft());
255   CU_ASSERT(32 == pchunks.rleft_buffered());
256 }
257 
test_peek_memchunks_disable_peek_drain(void)258 void test_peek_memchunks_disable_peek_drain(void) {
259   MemchunkPool16 pool;
260   PeekMemchunks16 pchunks(&pool);
261 
262   std::array<uint8_t, 32> b{
263       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
264       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
265   },
266       d;
267 
268   pchunks.append(b.data(), b.size());
269 
270   CU_ASSERT(12 == pchunks.remove(d.data(), 12));
271 
272   pchunks.disable_peek(true);
273 
274   CU_ASSERT(!pchunks.peeking);
275   CU_ASSERT(20 == pchunks.rleft());
276   CU_ASSERT(20 == pchunks.rleft_buffered());
277 
278   CU_ASSERT(20 == pchunks.remove(d.data(), d.size()));
279 
280   CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
281 
282   CU_ASSERT(0 == pchunks.rleft());
283   CU_ASSERT(0 == pchunks.rleft_buffered());
284 }
285 
test_peek_memchunks_disable_peek_no_drain(void)286 void test_peek_memchunks_disable_peek_no_drain(void) {
287   MemchunkPool16 pool;
288   PeekMemchunks16 pchunks(&pool);
289 
290   std::array<uint8_t, 32> b{
291       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
292       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
293   },
294       d;
295 
296   pchunks.append(b.data(), b.size());
297 
298   CU_ASSERT(12 == pchunks.remove(d.data(), 12));
299 
300   pchunks.disable_peek(false);
301 
302   CU_ASSERT(!pchunks.peeking);
303   CU_ASSERT(32 == pchunks.rleft());
304   CU_ASSERT(32 == pchunks.rleft_buffered());
305 
306   CU_ASSERT(32 == pchunks.remove(d.data(), d.size()));
307 
308   CU_ASSERT(std::equal(std::begin(b), std::end(b), std::begin(d)));
309 
310   CU_ASSERT(0 == pchunks.rleft());
311   CU_ASSERT(0 == pchunks.rleft_buffered());
312 }
313 
test_peek_memchunks_reset(void)314 void test_peek_memchunks_reset(void) {
315   MemchunkPool16 pool;
316   PeekMemchunks16 pchunks(&pool);
317 
318   std::array<uint8_t, 32> b{
319       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
320       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
321   },
322       d;
323 
324   pchunks.append(b.data(), b.size());
325 
326   CU_ASSERT(12 == pchunks.remove(d.data(), 12));
327 
328   pchunks.disable_peek(true);
329   pchunks.reset();
330 
331   CU_ASSERT(0 == pchunks.rleft());
332   CU_ASSERT(0 == pchunks.rleft_buffered());
333 
334   CU_ASSERT(nullptr == pchunks.cur);
335   CU_ASSERT(nullptr == pchunks.cur_pos);
336   CU_ASSERT(nullptr == pchunks.cur_last);
337   CU_ASSERT(pchunks.peeking);
338 }
339 
340 } // namespace nghttp2
341