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