• 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 "munitxx.h"
28 
29 #include <nghttp2/nghttp2.h>
30 
31 #include "memchunk.h"
32 #include "util.h"
33 
34 namespace nghttp2 {
35 
36 namespace {
37 const MunitTest tests[]{
38     munit_void_test(test_pool_recycle),
39     munit_void_test(test_memchunks_append),
40     munit_void_test(test_memchunks_drain),
41     munit_void_test(test_memchunks_riovec),
42     munit_void_test(test_memchunks_recycle),
43     munit_void_test(test_memchunks_reset),
44     munit_void_test(test_peek_memchunks_append),
45     munit_void_test(test_peek_memchunks_disable_peek_drain),
46     munit_void_test(test_peek_memchunks_disable_peek_no_drain),
47     munit_void_test(test_peek_memchunks_reset),
48     munit_test_end(),
49 };
50 } // namespace
51 
52 const MunitSuite memchunk_suite{
53     "/memchunk", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
54 };
55 
test_pool_recycle(void)56 void test_pool_recycle(void) {
57   MemchunkPool pool;
58 
59   assert_null(pool.pool);
60   assert_size(0, ==, pool.poolsize);
61   assert_null(pool.freelist);
62 
63   auto m1 = pool.get();
64 
65   assert_ptr_equal(m1, pool.pool);
66   assert_size(MemchunkPool::value_type::size, ==, pool.poolsize);
67   assert_null(pool.freelist);
68 
69   auto m2 = pool.get();
70 
71   assert_ptr_equal(m2, pool.pool);
72   assert_size(2 * MemchunkPool::value_type::size, ==, pool.poolsize);
73   assert_null(pool.freelist);
74   assert_ptr_equal(m1, m2->knext);
75   assert_null(m1->knext);
76 
77   auto m3 = pool.get();
78 
79   assert_ptr_equal(m3, pool.pool);
80   assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
81   assert_null(pool.freelist);
82 
83   pool.recycle(m3);
84 
85   assert_ptr_equal(m3, pool.pool);
86   assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
87   assert_ptr_equal(m3, pool.freelist);
88 
89   auto m4 = pool.get();
90 
91   assert_ptr_equal(m3, m4);
92   assert_ptr_equal(m4, pool.pool);
93   assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize);
94   assert_null(pool.freelist);
95 
96   pool.recycle(m2);
97   pool.recycle(m1);
98 
99   assert_ptr_equal(m1, pool.freelist);
100   assert_ptr_equal(m2, m1->next);
101   assert_null(m2->next);
102 }
103 
104 using Memchunk16 = Memchunk<16>;
105 using MemchunkPool16 = Pool<Memchunk16>;
106 using Memchunks16 = Memchunks<Memchunk16>;
107 using PeekMemchunks16 = PeekMemchunks<Memchunk16>;
108 
test_memchunks_append(void)109 void test_memchunks_append(void) {
110   MemchunkPool16 pool;
111   Memchunks16 chunks(&pool);
112 
113   chunks.append("012");
114 
115   auto m = chunks.tail;
116 
117   assert_size(3, ==, m->len());
118   assert_size(13, ==, m->left());
119 
120   chunks.append("3456789abcdef@");
121 
122   assert_size(16, ==, m->len());
123   assert_size(0, ==, m->left());
124 
125   m = chunks.tail;
126 
127   assert_size(1, ==, m->len());
128   assert_size(15, ==, m->left());
129   assert_size(17, ==, chunks.rleft());
130 
131   char buf[16];
132   size_t nread;
133 
134   nread = chunks.remove(buf, 8);
135 
136   assert_size(8, ==, nread);
137   assert_memory_equal(nread, "01234567", buf);
138   assert_size(9, ==, chunks.rleft());
139 
140   nread = chunks.remove(buf, sizeof(buf));
141 
142   assert_size(9, ==, nread);
143   assert_memory_equal(nread, "89abcdef@", buf);
144   assert_size(0, ==, chunks.rleft());
145   assert_null(chunks.head);
146   assert_null(chunks.tail);
147   assert_size(32, ==, pool.poolsize);
148 }
149 
test_memchunks_drain(void)150 void test_memchunks_drain(void) {
151   MemchunkPool16 pool;
152   Memchunks16 chunks(&pool);
153 
154   chunks.append("0123456789");
155 
156   size_t nread;
157 
158   nread = chunks.drain(3);
159 
160   assert_size(3, ==, nread);
161 
162   char buf[16];
163 
164   nread = chunks.remove(buf, sizeof(buf));
165 
166   assert_size(7, ==, nread);
167   assert_memory_equal(nread, "3456789", buf);
168 }
169 
test_memchunks_riovec(void)170 void test_memchunks_riovec(void) {
171   MemchunkPool16 pool;
172   Memchunks16 chunks(&pool);
173 
174   std::array<char, 3 * 16> buf{};
175 
176   chunks.append(buf.data(), buf.size());
177 
178   std::array<struct iovec, 2> iov;
179   auto iovcnt = chunks.riovec(iov.data(), iov.size());
180 
181   auto m = chunks.head;
182 
183   assert_int(2, ==, iovcnt);
184   assert_ptr_equal(m->buf.data(), iov[0].iov_base);
185   assert_size(m->len(), ==, iov[0].iov_len);
186 
187   m = m->next;
188 
189   assert_ptr_equal(m->buf.data(), iov[1].iov_base);
190   assert_size(m->len(), ==, iov[1].iov_len);
191 
192   chunks.drain(2 * 16);
193 
194   iovcnt = chunks.riovec(iov.data(), iov.size());
195 
196   assert_int(1, ==, iovcnt);
197 
198   m = chunks.head;
199   assert_ptr_equal(m->buf.data(), iov[0].iov_base);
200   assert_size(m->len(), ==, iov[0].iov_len);
201 }
202 
test_memchunks_recycle(void)203 void test_memchunks_recycle(void) {
204   MemchunkPool16 pool;
205   {
206     Memchunks16 chunks(&pool);
207     std::array<char, 32> buf{};
208     chunks.append(buf.data(), buf.size());
209   }
210   assert_size(32, ==, pool.poolsize);
211   assert_not_null(pool.freelist);
212 
213   auto m = pool.freelist;
214   m = m->next;
215 
216   assert_not_null(m);
217   assert_null(m->next);
218 }
219 
test_memchunks_reset(void)220 void test_memchunks_reset(void) {
221   MemchunkPool16 pool;
222   Memchunks16 chunks(&pool);
223 
224   std::array<uint8_t, 32> b{};
225 
226   chunks.append(b.data(), b.size());
227 
228   assert_size(32, ==, chunks.rleft());
229 
230   chunks.reset();
231 
232   assert_size(0, ==, chunks.rleft());
233   assert_null(chunks.head);
234   assert_null(chunks.tail);
235 
236   auto m = pool.freelist;
237 
238   assert_not_null(m);
239   assert_not_null(m->next);
240   assert_null(m->next->next);
241 }
242 
test_peek_memchunks_append(void)243 void test_peek_memchunks_append(void) {
244   MemchunkPool16 pool;
245   PeekMemchunks16 pchunks(&pool);
246 
247   std::array<uint8_t, 32> b{
248       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
249       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
250   },
251       d;
252 
253   pchunks.append(b.data(), b.size());
254 
255   assert_size(32, ==, pchunks.rleft());
256   assert_size(32, ==, pchunks.rleft_buffered());
257 
258   assert_size(0, ==, pchunks.remove(nullptr, 0));
259 
260   assert_size(32, ==, pchunks.rleft());
261   assert_size(32, ==, pchunks.rleft_buffered());
262 
263   assert_size(12, ==, pchunks.remove(d.data(), 12));
264 
265   assert_true(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d)));
266 
267   assert_size(20, ==, pchunks.rleft());
268   assert_size(32, ==, pchunks.rleft_buffered());
269 
270   assert_size(20, ==, pchunks.remove(d.data(), d.size()));
271 
272   assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
273 
274   assert_size(0, ==, pchunks.rleft());
275   assert_size(32, ==, pchunks.rleft_buffered());
276 }
277 
test_peek_memchunks_disable_peek_drain(void)278 void test_peek_memchunks_disable_peek_drain(void) {
279   MemchunkPool16 pool;
280   PeekMemchunks16 pchunks(&pool);
281 
282   std::array<uint8_t, 32> b{
283       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
284       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
285   },
286       d;
287 
288   pchunks.append(b.data(), b.size());
289 
290   assert_size(12, ==, pchunks.remove(d.data(), 12));
291 
292   pchunks.disable_peek(true);
293 
294   assert_false(pchunks.peeking);
295   assert_size(20, ==, pchunks.rleft());
296   assert_size(20, ==, pchunks.rleft_buffered());
297 
298   assert_size(20, ==, pchunks.remove(d.data(), d.size()));
299 
300   assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d)));
301 
302   assert_size(0, ==, pchunks.rleft());
303   assert_size(0, ==, pchunks.rleft_buffered());
304 }
305 
test_peek_memchunks_disable_peek_no_drain(void)306 void test_peek_memchunks_disable_peek_no_drain(void) {
307   MemchunkPool16 pool;
308   PeekMemchunks16 pchunks(&pool);
309 
310   std::array<uint8_t, 32> b{
311       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
312       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
313   },
314       d;
315 
316   pchunks.append(b.data(), b.size());
317 
318   assert_size(12, ==, pchunks.remove(d.data(), 12));
319 
320   pchunks.disable_peek(false);
321 
322   assert_false(pchunks.peeking);
323   assert_size(32, ==, pchunks.rleft());
324   assert_size(32, ==, pchunks.rleft_buffered());
325 
326   assert_size(32, ==, pchunks.remove(d.data(), d.size()));
327 
328   assert_true(std::equal(std::begin(b), std::end(b), std::begin(d)));
329 
330   assert_size(0, ==, pchunks.rleft());
331   assert_size(0, ==, pchunks.rleft_buffered());
332 }
333 
test_peek_memchunks_reset(void)334 void test_peek_memchunks_reset(void) {
335   MemchunkPool16 pool;
336   PeekMemchunks16 pchunks(&pool);
337 
338   std::array<uint8_t, 32> b{
339       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
340       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
341   },
342       d;
343 
344   pchunks.append(b.data(), b.size());
345 
346   assert_size(12, ==, pchunks.remove(d.data(), 12));
347 
348   pchunks.disable_peek(true);
349   pchunks.reset();
350 
351   assert_size(0, ==, pchunks.rleft());
352   assert_size(0, ==, pchunks.rleft_buffered());
353 
354   assert_null(pchunks.cur);
355   assert_null(pchunks.cur_pos);
356   assert_null(pchunks.cur_last);
357   assert_true(pchunks.peeking);
358 }
359 
360 } // namespace nghttp2
361