Fix copyright lines
[folly.git] / folly / io / test / IOBufQueueTest.cpp
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/io/IOBufQueue.h>
18
19 #include <cstring>
20 #include <iostream>
21 #include <stdexcept>
22
23 #include <folly/Range.h>
24 #include <folly/portability/GTest.h>
25
26 using folly::IOBuf;
27 using folly::IOBufQueue;
28 using folly::StringPiece;
29 using std::pair;
30 using std::string;
31 using std::unique_ptr;
32
33 // String Comma Length macro for string literals
34 #define SCL(x) (x), sizeof(x) - 1
35
36 namespace {
37
38 IOBufQueue::Options clOptions;
39 struct Initializer {
40   Initializer() {
41     clOptions.cacheChainLength = true;
42   }
43 };
44 Initializer initializer;
45
46 unique_ptr<IOBuf> stringToIOBuf(const char* s, size_t len) {
47   unique_ptr<IOBuf> buf = IOBuf::create(len);
48   memcpy(buf->writableTail(), s, len);
49   buf->append(len);
50   return buf;
51 }
52
53 void checkConsistency(const IOBufQueue& queue) {
54   if (queue.options().cacheChainLength) {
55     size_t len = queue.front() ? queue.front()->computeChainDataLength() : 0;
56     EXPECT_EQ(len, queue.chainLength());
57   }
58 }
59
60 } // namespace
61
62 TEST(IOBufQueue, Simple) {
63   IOBufQueue queue(clOptions);
64   EXPECT_EQ(nullptr, queue.front());
65   queue.append(SCL(""));
66   EXPECT_EQ(nullptr, queue.front());
67   queue.append(unique_ptr<IOBuf>());
68   EXPECT_EQ(nullptr, queue.front());
69   string emptyString;
70   queue.append(emptyString);
71   EXPECT_EQ(nullptr, queue.front());
72 }
73
74 TEST(IOBufQueue, Append) {
75   IOBufQueue queue(clOptions);
76   queue.append(SCL("Hello"));
77   IOBufQueue queue2(clOptions);
78   queue2.append(SCL(", "));
79   queue2.append(SCL("World"));
80   checkConsistency(queue);
81   checkConsistency(queue2);
82   queue.append(queue2.move());
83   checkConsistency(queue);
84   checkConsistency(queue2);
85   const IOBuf* chain = queue.front();
86   EXPECT_NE((IOBuf*)nullptr, chain);
87   EXPECT_EQ(12, chain->computeChainDataLength());
88   EXPECT_EQ(nullptr, queue2.front());
89 }
90
91 TEST(IOBufQueue, Append2) {
92   IOBufQueue queue(clOptions);
93   queue.append(SCL("Hello"));
94   IOBufQueue queue2(clOptions);
95   queue2.append(SCL(", "));
96   queue2.append(SCL("World"));
97   checkConsistency(queue);
98   checkConsistency(queue2);
99   queue.append(queue2);
100   checkConsistency(queue);
101   checkConsistency(queue2);
102   const IOBuf* chain = queue.front();
103   EXPECT_NE((IOBuf*)nullptr, chain);
104   EXPECT_EQ(12, chain->computeChainDataLength());
105   EXPECT_EQ(nullptr, queue2.front());
106 }
107
108 TEST(IOBufQueue, AppendStringPiece) {
109   std::string s("Hello, World");
110   IOBufQueue queue(clOptions);
111   IOBufQueue queue2(clOptions);
112   queue.append(s.data(), s.length());
113   queue2.append(s);
114   checkConsistency(queue);
115   checkConsistency(queue2);
116   const IOBuf* chain = queue.front();
117   const IOBuf* chain2 = queue2.front();
118   EXPECT_EQ(s.length(), chain->computeChainDataLength());
119   EXPECT_EQ(s.length(), chain2->computeChainDataLength());
120   EXPECT_EQ(0, memcmp(chain->data(), chain2->data(), s.length()));
121 }
122
123 TEST(IOBufQueue, Split) {
124   IOBufQueue queue(clOptions);
125   queue.append(stringToIOBuf(SCL("Hello")));
126   queue.append(stringToIOBuf(SCL(",")));
127   queue.append(stringToIOBuf(SCL(" ")));
128   queue.append(stringToIOBuf(SCL("")));
129   queue.append(stringToIOBuf(SCL("World")));
130   checkConsistency(queue);
131   EXPECT_EQ(12, queue.front()->computeChainDataLength());
132
133   unique_ptr<IOBuf> prefix(queue.split(1));
134   checkConsistency(queue);
135   EXPECT_EQ(1, prefix->computeChainDataLength());
136   EXPECT_EQ(11, queue.front()->computeChainDataLength());
137   prefix = queue.split(2);
138   checkConsistency(queue);
139   EXPECT_EQ(2, prefix->computeChainDataLength());
140   EXPECT_EQ(9, queue.front()->computeChainDataLength());
141   prefix = queue.split(3);
142   checkConsistency(queue);
143   EXPECT_EQ(3, prefix->computeChainDataLength());
144   EXPECT_EQ(6, queue.front()->computeChainDataLength());
145   prefix = queue.split(1);
146   checkConsistency(queue);
147   EXPECT_EQ(1, prefix->computeChainDataLength());
148   EXPECT_EQ(5, queue.front()->computeChainDataLength());
149   prefix = queue.split(5);
150   checkConsistency(queue);
151   EXPECT_EQ(5, prefix->computeChainDataLength());
152   EXPECT_EQ((IOBuf*)nullptr, queue.front());
153
154   queue.append(stringToIOBuf(SCL("Hello,")));
155   queue.append(stringToIOBuf(SCL(" World")));
156   checkConsistency(queue);
157   EXPECT_THROW({prefix = queue.split(13);}, std::underflow_error);
158   checkConsistency(queue);
159 }
160
161 TEST(IOBufQueue, SplitAtMost) {
162   IOBufQueue queue(clOptions);
163   queue.append(stringToIOBuf(SCL("Hello,")));
164   queue.append(stringToIOBuf(SCL(" World")));
165   auto buf = queue.splitAtMost(9999);
166   EXPECT_EQ(buf->computeChainDataLength(), 12);
167   EXPECT_TRUE(queue.empty());
168 }
169
170 TEST(IOBufQueue, SplitZero) {
171   IOBufQueue queue(clOptions);
172   queue.append(stringToIOBuf(SCL("Hello world")));
173   auto buf = queue.split(0);
174   EXPECT_EQ(buf->computeChainDataLength(), 0);
175 }
176
177 TEST(IOBufQueue, Preallocate) {
178   IOBufQueue queue(clOptions);
179   queue.append(string("Hello"));
180   pair<void*, uint64_t> writable = queue.preallocate(2, 64, 64);
181   checkConsistency(queue);
182   EXPECT_NE((void*)nullptr, writable.first);
183   EXPECT_LE(2, writable.second);
184   EXPECT_GE(64, writable.second);
185   memcpy(writable.first, SCL(", "));
186   queue.postallocate(2);
187   checkConsistency(queue);
188   EXPECT_EQ(7, queue.front()->computeChainDataLength());
189   queue.append(SCL("World"));
190   checkConsistency(queue);
191   EXPECT_EQ(12, queue.front()->computeChainDataLength());
192   // There are not 2048 bytes available, this will alloc a new buf
193   writable = queue.preallocate(2048, 4096);
194   checkConsistency(queue);
195   EXPECT_LE(2048, writable.second);
196   // IOBuf allocates more than newAllocationSize, and we didn't cap it
197   EXPECT_GE(writable.second, 4096);
198   queue.postallocate(writable.second);
199   // queue has no empty space, make sure we allocate at least min, even if
200   // newAllocationSize < min
201   writable = queue.preallocate(1024, 1, 1024);
202   checkConsistency(queue);
203   EXPECT_EQ(1024, writable.second);
204 }
205
206 TEST(IOBufQueue, Wrap) {
207   IOBufQueue queue(clOptions);
208   const char* buf = "hello world goodbye";
209   size_t len = strlen(buf);
210   queue.wrapBuffer(buf, len, 6);
211   auto iob = queue.move();
212   EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
213   iob->unshare();
214   iob->coalesce();
215   EXPECT_EQ(StringPiece(buf),
216             StringPiece(reinterpret_cast<const char*>(iob->data()),
217                         iob->length()));
218 }
219
220 TEST(IOBufQueue, Trim) {
221   IOBufQueue queue(clOptions);
222   unique_ptr<IOBuf> a = IOBuf::create(4);
223   a->append(4);
224   queue.append(std::move(a));
225   checkConsistency(queue);
226   a = IOBuf::create(6);
227   a->append(6);
228   queue.append(std::move(a));
229   checkConsistency(queue);
230   a = IOBuf::create(8);
231   a->append(8);
232   queue.append(std::move(a));
233   checkConsistency(queue);
234   a = IOBuf::create(10);
235   a->append(10);
236   queue.append(std::move(a));
237   checkConsistency(queue);
238
239   EXPECT_EQ(4, queue.front()->countChainElements());
240   EXPECT_EQ(28, queue.front()->computeChainDataLength());
241   EXPECT_EQ(4, queue.front()->length());
242
243   queue.trimStart(1);
244   checkConsistency(queue);
245   EXPECT_EQ(4, queue.front()->countChainElements());
246   EXPECT_EQ(27, queue.front()->computeChainDataLength());
247   EXPECT_EQ(3, queue.front()->length());
248
249   queue.trimStart(5);
250   checkConsistency(queue);
251   EXPECT_EQ(3, queue.front()->countChainElements());
252   EXPECT_EQ(22, queue.front()->computeChainDataLength());
253   EXPECT_EQ(4, queue.front()->length());
254
255   queue.trimEnd(1);
256   checkConsistency(queue);
257   EXPECT_EQ(3, queue.front()->countChainElements());
258   EXPECT_EQ(21, queue.front()->computeChainDataLength());
259   EXPECT_EQ(9, queue.front()->prev()->length());
260
261   queue.trimEnd(20);
262   checkConsistency(queue);
263   EXPECT_EQ(1, queue.front()->countChainElements());
264   EXPECT_EQ(1, queue.front()->computeChainDataLength());
265   EXPECT_EQ(1, queue.front()->prev()->length());
266
267   queue.trimEnd(1);
268   checkConsistency(queue);
269   EXPECT_EQ(nullptr, queue.front());
270
271   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
272   checkConsistency(queue);
273
274   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
275   checkConsistency(queue);
276 }
277
278 TEST(IOBufQueue, TrimStartAtMost) {
279   IOBufQueue queue(clOptions);
280   unique_ptr<IOBuf> a = IOBuf::create(4);
281   a->append(4);
282   queue.append(std::move(a));
283   checkConsistency(queue);
284   a = IOBuf::create(6);
285   a->append(6);
286   queue.append(std::move(a));
287   checkConsistency(queue);
288   a = IOBuf::create(8);
289   a->append(8);
290   queue.append(std::move(a));
291   checkConsistency(queue);
292   a = IOBuf::create(10);
293   a->append(10);
294   queue.append(std::move(a));
295   checkConsistency(queue);
296
297   EXPECT_EQ(4, queue.front()->countChainElements());
298   EXPECT_EQ(28, queue.front()->computeChainDataLength());
299   EXPECT_EQ(4, queue.front()->length());
300
301   queue.trimStartAtMost(1);
302   checkConsistency(queue);
303   EXPECT_EQ(4, queue.front()->countChainElements());
304   EXPECT_EQ(27, queue.front()->computeChainDataLength());
305   EXPECT_EQ(3, queue.front()->length());
306
307   queue.trimStartAtMost(50);
308   checkConsistency(queue);
309   EXPECT_EQ(nullptr, queue.front());
310   EXPECT_EQ(0, queue.chainLength());
311 }
312
313 TEST(IOBufQueue, TrimEndAtMost) {
314   IOBufQueue queue(clOptions);
315   unique_ptr<IOBuf> a = IOBuf::create(4);
316   a->append(4);
317   queue.append(std::move(a));
318   checkConsistency(queue);
319   a = IOBuf::create(6);
320   a->append(6);
321   queue.append(std::move(a));
322   checkConsistency(queue);
323   a = IOBuf::create(8);
324   a->append(8);
325   queue.append(std::move(a));
326   checkConsistency(queue);
327   a = IOBuf::create(10);
328   a->append(10);
329   queue.append(std::move(a));
330   checkConsistency(queue);
331
332   EXPECT_EQ(4, queue.front()->countChainElements());
333   EXPECT_EQ(28, queue.front()->computeChainDataLength());
334   EXPECT_EQ(4, queue.front()->length());
335
336   queue.trimEndAtMost(1);
337   checkConsistency(queue);
338   EXPECT_EQ(4, queue.front()->countChainElements());
339   EXPECT_EQ(27, queue.front()->computeChainDataLength());
340   EXPECT_EQ(4, queue.front()->length());
341
342   queue.trimEndAtMost(50);
343   checkConsistency(queue);
344   EXPECT_EQ(nullptr, queue.front());
345   EXPECT_EQ(0, queue.chainLength());
346 }
347
348 TEST(IOBufQueue, TrimPack) {
349   IOBufQueue queue(clOptions);
350   unique_ptr<IOBuf> a = IOBuf::create(64);
351   a->append(4);
352   queue.append(std::move(a), true);
353   checkConsistency(queue);
354   a = IOBuf::create(6);
355   a->append(6);
356   queue.append(std::move(a), true);
357   checkConsistency(queue);
358   a = IOBuf::create(8);
359   a->append(8);
360   queue.append(std::move(a), true);
361   checkConsistency(queue);
362   a = IOBuf::create(10);
363   a->append(10);
364   queue.append(std::move(a), true);
365   checkConsistency(queue);
366
367   EXPECT_EQ(1, queue.front()->countChainElements());
368   EXPECT_EQ(28, queue.front()->computeChainDataLength());
369   EXPECT_EQ(28, queue.front()->length());
370
371   queue.trimStart(1);
372   checkConsistency(queue);
373   EXPECT_EQ(1, queue.front()->countChainElements());
374   EXPECT_EQ(27, queue.front()->computeChainDataLength());
375   EXPECT_EQ(27, queue.front()->length());
376
377   queue.trimStart(5);
378   checkConsistency(queue);
379   EXPECT_EQ(1, queue.front()->countChainElements());
380   EXPECT_EQ(22, queue.front()->computeChainDataLength());
381   EXPECT_EQ(22, queue.front()->length());
382
383   queue.trimEnd(1);
384   checkConsistency(queue);
385   EXPECT_EQ(1, queue.front()->countChainElements());
386   EXPECT_EQ(21, queue.front()->computeChainDataLength());
387   EXPECT_EQ(21, queue.front()->prev()->length());
388
389   queue.trimEnd(20);
390   checkConsistency(queue);
391   EXPECT_EQ(1, queue.front()->countChainElements());
392   EXPECT_EQ(1, queue.front()->computeChainDataLength());
393   EXPECT_EQ(1, queue.front()->prev()->length());
394
395   queue.trimEnd(1);
396   checkConsistency(queue);
397   EXPECT_EQ(nullptr, queue.front());
398
399   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
400   checkConsistency(queue);
401
402   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
403   checkConsistency(queue);
404 }
405
406 TEST(IOBufQueue, Prepend) {
407   folly::IOBufQueue queue;
408
409   auto buf = folly::IOBuf::create(10);
410   buf->advance(5);
411   queue.append(std::move(buf));
412
413   queue.append(SCL(" World"));
414   queue.prepend(SCL("Hello"));
415
416   EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
417
418   auto out = queue.move();
419   out->coalesce();
420   EXPECT_EQ("Hello World",
421             StringPiece(reinterpret_cast<const char*>(out->data()),
422                         out->length()));
423 }
424
425 TEST(IOBufQueue, PopFirst) {
426   IOBufQueue queue(IOBufQueue::cacheChainLength());
427   const char * strings[] = {
428     "Hello",
429     ",",
430     " ",
431     "",
432     "World"
433   };
434
435   const size_t numStrings=sizeof(strings)/sizeof(*strings);
436   size_t chainLength = 0;
437   for(size_t i = 0; i < numStrings; ++i) {
438     queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
439     checkConsistency(queue);
440     chainLength += strlen(strings[i]);
441   }
442
443   unique_ptr<IOBuf> first;
444   for(size_t i = 0; i < numStrings; ++i) {
445     checkConsistency(queue);
446     EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
447     EXPECT_EQ(chainLength, queue.chainLength());
448     first = queue.pop_front();
449     chainLength-=strlen(strings[i]);
450     EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
451   }
452   checkConsistency(queue);
453   EXPECT_EQ(chainLength, queue.chainLength());
454
455   EXPECT_EQ((IOBuf*)nullptr, queue.front());
456   first = queue.pop_front();
457   EXPECT_EQ((IOBuf*)nullptr, first.get());
458
459   checkConsistency(queue);
460   EXPECT_EQ((IOBuf*)nullptr, queue.front());
461   EXPECT_EQ(0, queue.chainLength());
462 }
463
464 TEST(IOBufQueue, AppendToString) {
465   IOBufQueue queue;
466   queue.append("hello ", 6);
467   queue.append("world", 5);
468   std::string s;
469   queue.appendToString(s);
470   EXPECT_EQ("hello world", s);
471 }
472
473 TEST(IOBufQueue, Gather) {
474   IOBufQueue queue;
475
476   queue.append(stringToIOBuf(SCL("hello ")));
477   queue.append(stringToIOBuf(SCL("world")));
478
479   EXPECT_EQ(queue.front()->length(), 6);
480   queue.gather(11);
481   EXPECT_EQ(queue.front()->length(), 11);
482
483   StringPiece s(
484       reinterpret_cast<const char*>(queue.front()->data()),
485       queue.front()->length());
486   EXPECT_EQ("hello world", s);
487 }