2017
[folly.git] / folly / io / test / IOBufQueueTest.cpp
1 /*
2  * Copyright 2017 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 <iostream>
20 #include <stdexcept>
21 #include <string.h>
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>
47 stringToIOBuf(const char* s, uint32_t len) {
48   unique_ptr<IOBuf> buf = IOBuf::create(len);
49   memcpy(buf->writableTail(), s, len);
50   buf->append(len);
51   return buf;
52 }
53
54 void checkConsistency(const IOBufQueue& queue) {
55   if (queue.options().cacheChainLength) {
56     size_t len = queue.front() ? queue.front()->computeChainDataLength() : 0;
57     EXPECT_EQ(len, queue.chainLength());
58   }
59 }
60
61 }
62
63 TEST(IOBufQueue, Simple) {
64   IOBufQueue queue(clOptions);
65   EXPECT_EQ(nullptr, queue.front());
66   queue.append(SCL(""));
67   EXPECT_EQ(nullptr, queue.front());
68   queue.append(unique_ptr<IOBuf>());
69   EXPECT_EQ(nullptr, queue.front());
70   string emptyString;
71   queue.append(emptyString);
72   EXPECT_EQ(nullptr, queue.front());
73 }
74
75 TEST(IOBufQueue, Append) {
76   IOBufQueue queue(clOptions);
77   queue.append(SCL("Hello"));
78   IOBufQueue queue2(clOptions);
79   queue2.append(SCL(", "));
80   queue2.append(SCL("World"));
81   checkConsistency(queue);
82   checkConsistency(queue2);
83   queue.append(queue2.move());
84   checkConsistency(queue);
85   checkConsistency(queue2);
86   const IOBuf* chain = queue.front();
87   EXPECT_NE((IOBuf*)nullptr, chain);
88   EXPECT_EQ(12, chain->computeChainDataLength());
89   EXPECT_EQ(nullptr, queue2.front());
90 }
91
92 TEST(IOBufQueue, Append2) {
93   IOBufQueue queue(clOptions);
94   queue.append(SCL("Hello"));
95   IOBufQueue queue2(clOptions);
96   queue2.append(SCL(", "));
97   queue2.append(SCL("World"));
98   checkConsistency(queue);
99   checkConsistency(queue2);
100   queue.append(queue2);
101   checkConsistency(queue);
102   checkConsistency(queue2);
103   const IOBuf* chain = queue.front();
104   EXPECT_NE((IOBuf*)nullptr, chain);
105   EXPECT_EQ(12, chain->computeChainDataLength());
106   EXPECT_EQ(nullptr, queue2.front());
107 }
108
109 TEST(IOBufQueue, AppendStringPiece) {
110   std::string s("Hello, World");
111   IOBufQueue queue(clOptions);
112   IOBufQueue queue2(clOptions);
113   queue.append(s.data(), s.length());
114   queue2.append(s);
115   checkConsistency(queue);
116   checkConsistency(queue2);
117   const IOBuf* chain = queue.front();
118   const IOBuf* chain2 = queue2.front();
119   EXPECT_EQ(s.length(), chain->computeChainDataLength());
120   EXPECT_EQ(s.length(), chain2->computeChainDataLength());
121   EXPECT_EQ(0, memcmp(chain->data(), chain2->data(), s.length()));
122 }
123
124 TEST(IOBufQueue, Split) {
125   IOBufQueue queue(clOptions);
126   queue.append(stringToIOBuf(SCL("Hello")));
127   queue.append(stringToIOBuf(SCL(",")));
128   queue.append(stringToIOBuf(SCL(" ")));
129   queue.append(stringToIOBuf(SCL("")));
130   queue.append(stringToIOBuf(SCL("World")));
131   checkConsistency(queue);
132   EXPECT_EQ(12, queue.front()->computeChainDataLength());
133
134   unique_ptr<IOBuf> prefix(queue.split(1));
135   checkConsistency(queue);
136   EXPECT_EQ(1, prefix->computeChainDataLength());
137   EXPECT_EQ(11, queue.front()->computeChainDataLength());
138   prefix = queue.split(2);
139   checkConsistency(queue);
140   EXPECT_EQ(2, prefix->computeChainDataLength());
141   EXPECT_EQ(9, queue.front()->computeChainDataLength());
142   prefix = queue.split(3);
143   checkConsistency(queue);
144   EXPECT_EQ(3, prefix->computeChainDataLength());
145   EXPECT_EQ(6, queue.front()->computeChainDataLength());
146   prefix = queue.split(1);
147   checkConsistency(queue);
148   EXPECT_EQ(1, prefix->computeChainDataLength());
149   EXPECT_EQ(5, queue.front()->computeChainDataLength());
150   prefix = queue.split(5);
151   checkConsistency(queue);
152   EXPECT_EQ(5, prefix->computeChainDataLength());
153   EXPECT_EQ((IOBuf*)nullptr, queue.front());
154
155   queue.append(stringToIOBuf(SCL("Hello,")));
156   queue.append(stringToIOBuf(SCL(" World")));
157   checkConsistency(queue);
158   EXPECT_THROW({prefix = queue.split(13);}, std::underflow_error);
159   checkConsistency(queue);
160 }
161
162 TEST(IOBufQueue, SplitAtMost) {
163   IOBufQueue queue(clOptions);
164   queue.append(stringToIOBuf(SCL("Hello,")));
165   queue.append(stringToIOBuf(SCL(" World")));
166   auto buf = queue.splitAtMost(9999);
167   EXPECT_EQ(buf->computeChainDataLength(), 12);
168   EXPECT_TRUE(queue.empty());
169 }
170
171 TEST(IOBufQueue, Preallocate) {
172   IOBufQueue queue(clOptions);
173   queue.append(string("Hello"));
174   pair<void*,uint32_t> writable = queue.preallocate(2, 64, 64);
175   checkConsistency(queue);
176   EXPECT_NE((void*)nullptr, writable.first);
177   EXPECT_LE(2, writable.second);
178   EXPECT_GE(64, writable.second);
179   memcpy(writable.first, SCL(", "));
180   queue.postallocate(2);
181   checkConsistency(queue);
182   EXPECT_EQ(7, queue.front()->computeChainDataLength());
183   queue.append(SCL("World"));
184   checkConsistency(queue);
185   EXPECT_EQ(12, queue.front()->computeChainDataLength());
186   // There are not 2048 bytes available, this will alloc a new buf
187   writable = queue.preallocate(2048, 4096);
188   checkConsistency(queue);
189   EXPECT_LE(2048, writable.second);
190   // IOBuf allocates more than newAllocationSize, and we didn't cap it
191   EXPECT_GE(writable.second, 4096);
192   queue.postallocate(writable.second);
193   // queue has no empty space, make sure we allocate at least min, even if
194   // newAllocationSize < min
195   writable = queue.preallocate(1024, 1, 1024);
196   checkConsistency(queue);
197   EXPECT_EQ(1024, writable.second);
198 }
199
200 TEST(IOBufQueue, Wrap) {
201   IOBufQueue queue(clOptions);
202   const char* buf = "hello world goodbye";
203   size_t len = strlen(buf);
204   queue.wrapBuffer(buf, len, 6);
205   auto iob = queue.move();
206   EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
207   iob->unshare();
208   iob->coalesce();
209   EXPECT_EQ(StringPiece(buf),
210             StringPiece(reinterpret_cast<const char*>(iob->data()),
211                         iob->length()));
212 }
213
214 TEST(IOBufQueue, Trim) {
215   IOBufQueue queue(clOptions);
216   unique_ptr<IOBuf> a = IOBuf::create(4);
217   a->append(4);
218   queue.append(std::move(a));
219   checkConsistency(queue);
220   a = IOBuf::create(6);
221   a->append(6);
222   queue.append(std::move(a));
223   checkConsistency(queue);
224   a = IOBuf::create(8);
225   a->append(8);
226   queue.append(std::move(a));
227   checkConsistency(queue);
228   a = IOBuf::create(10);
229   a->append(10);
230   queue.append(std::move(a));
231   checkConsistency(queue);
232
233   EXPECT_EQ(4, queue.front()->countChainElements());
234   EXPECT_EQ(28, queue.front()->computeChainDataLength());
235   EXPECT_EQ(4, queue.front()->length());
236
237   queue.trimStart(1);
238   checkConsistency(queue);
239   EXPECT_EQ(4, queue.front()->countChainElements());
240   EXPECT_EQ(27, queue.front()->computeChainDataLength());
241   EXPECT_EQ(3, queue.front()->length());
242
243   queue.trimStart(5);
244   checkConsistency(queue);
245   EXPECT_EQ(3, queue.front()->countChainElements());
246   EXPECT_EQ(22, queue.front()->computeChainDataLength());
247   EXPECT_EQ(4, queue.front()->length());
248
249   queue.trimEnd(1);
250   checkConsistency(queue);
251   EXPECT_EQ(3, queue.front()->countChainElements());
252   EXPECT_EQ(21, queue.front()->computeChainDataLength());
253   EXPECT_EQ(9, queue.front()->prev()->length());
254
255   queue.trimEnd(20);
256   checkConsistency(queue);
257   EXPECT_EQ(1, queue.front()->countChainElements());
258   EXPECT_EQ(1, queue.front()->computeChainDataLength());
259   EXPECT_EQ(1, queue.front()->prev()->length());
260
261   queue.trimEnd(1);
262   checkConsistency(queue);
263   EXPECT_EQ(nullptr, queue.front());
264
265   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
266   checkConsistency(queue);
267
268   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
269   checkConsistency(queue);
270 }
271
272 TEST(IOBufQueue, TrimPack) {
273   IOBufQueue queue(clOptions);
274   unique_ptr<IOBuf> a = IOBuf::create(64);
275   a->append(4);
276   queue.append(std::move(a), true);
277   checkConsistency(queue);
278   a = IOBuf::create(6);
279   a->append(6);
280   queue.append(std::move(a), true);
281   checkConsistency(queue);
282   a = IOBuf::create(8);
283   a->append(8);
284   queue.append(std::move(a), true);
285   checkConsistency(queue);
286   a = IOBuf::create(10);
287   a->append(10);
288   queue.append(std::move(a), true);
289   checkConsistency(queue);
290
291   EXPECT_EQ(1, queue.front()->countChainElements());
292   EXPECT_EQ(28, queue.front()->computeChainDataLength());
293   EXPECT_EQ(28, queue.front()->length());
294
295   queue.trimStart(1);
296   checkConsistency(queue);
297   EXPECT_EQ(1, queue.front()->countChainElements());
298   EXPECT_EQ(27, queue.front()->computeChainDataLength());
299   EXPECT_EQ(27, queue.front()->length());
300
301   queue.trimStart(5);
302   checkConsistency(queue);
303   EXPECT_EQ(1, queue.front()->countChainElements());
304   EXPECT_EQ(22, queue.front()->computeChainDataLength());
305   EXPECT_EQ(22, queue.front()->length());
306
307   queue.trimEnd(1);
308   checkConsistency(queue);
309   EXPECT_EQ(1, queue.front()->countChainElements());
310   EXPECT_EQ(21, queue.front()->computeChainDataLength());
311   EXPECT_EQ(21, queue.front()->prev()->length());
312
313   queue.trimEnd(20);
314   checkConsistency(queue);
315   EXPECT_EQ(1, queue.front()->countChainElements());
316   EXPECT_EQ(1, queue.front()->computeChainDataLength());
317   EXPECT_EQ(1, queue.front()->prev()->length());
318
319   queue.trimEnd(1);
320   checkConsistency(queue);
321   EXPECT_EQ(nullptr, queue.front());
322
323   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
324   checkConsistency(queue);
325
326   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
327   checkConsistency(queue);
328 }
329
330 TEST(IOBufQueue, Prepend) {
331   folly::IOBufQueue queue;
332
333   auto buf = folly::IOBuf::create(10);
334   buf->advance(5);
335   queue.append(std::move(buf));
336
337   queue.append(SCL(" World"));
338   queue.prepend(SCL("Hello"));
339
340   EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
341
342   auto out = queue.move();
343   out->coalesce();
344   EXPECT_EQ("Hello World",
345             StringPiece(reinterpret_cast<const char*>(out->data()),
346                         out->length()));
347 }
348
349 TEST(IOBufQueue, PopFirst) {
350   IOBufQueue queue(IOBufQueue::cacheChainLength());
351   const char * strings[] = {
352     "Hello",
353     ",",
354     " ",
355     "",
356     "World"
357   };
358
359   const size_t numStrings=sizeof(strings)/sizeof(*strings);
360   size_t chainLength = 0;
361   for(size_t i = 0; i < numStrings; ++i) {
362     queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
363     checkConsistency(queue);
364     chainLength += strlen(strings[i]);
365   }
366
367   unique_ptr<IOBuf> first;
368   for(size_t i = 0; i < numStrings; ++i) {
369     checkConsistency(queue);
370     EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
371     EXPECT_EQ(chainLength, queue.chainLength());
372     first = queue.pop_front();
373     chainLength-=strlen(strings[i]);
374     EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
375   }
376   checkConsistency(queue);
377   EXPECT_EQ(chainLength, queue.chainLength());
378
379   EXPECT_EQ((IOBuf*)nullptr, queue.front());
380   first = queue.pop_front();
381   EXPECT_EQ((IOBuf*)nullptr, first.get());
382
383   checkConsistency(queue);
384   EXPECT_EQ((IOBuf*)nullptr, queue.front());
385   EXPECT_EQ(0, queue.chainLength());
386 }
387
388 TEST(IOBufQueue, AppendToString) {
389   IOBufQueue queue;
390   queue.append("hello ", 6);
391   queue.append("world", 5);
392   std::string s;
393   queue.appendToString(s);
394   EXPECT_EQ("hello world", s);
395 }
396
397 TEST(IOBufQueue, Gather) {
398   IOBufQueue queue;
399
400   queue.append(stringToIOBuf(SCL("hello ")));
401   queue.append(stringToIOBuf(SCL("world")));
402
403   EXPECT_EQ(queue.front()->length(), 6);
404   queue.gather(11);
405   EXPECT_EQ(queue.front()->length(), 11);
406
407   StringPiece s(
408       reinterpret_cast<const char*>(queue.front()->data()),
409       queue.front()->length());
410   EXPECT_EQ("hello world", s);
411 }