df2c03e1ce921f48274c6d30a15f55e7beb1c4a6
[folly.git] / folly / wangle / codec / CodecTest.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 #include <gtest/gtest.h>
17
18 #include <folly/wangle/codec/FixedLengthFrameDecoder.h>
19 #include <folly/wangle/codec/LengthFieldBasedFrameDecoder.h>
20 #include <folly/wangle/codec/LengthFieldPrepender.h>
21
22 using namespace folly;
23 using namespace folly::wangle;
24 using namespace folly::io;
25
26 class FrameTester
27     : public BytesToBytesHandler {
28  public:
29   FrameTester(std::function<void(std::unique_ptr<IOBuf>)> test)
30     : test_(test) {}
31
32   void read(Context* ctx, IOBufQueue& q) {
33     test_(q.move());
34   }
35  private:
36   std::function<void(std::unique_ptr<IOBuf>)> test_;
37 };
38
39 class BytesReflector
40     : public BytesToBytesHandler {
41  public:
42
43   Future<void> write(Context* ctx, std::unique_ptr<IOBuf> buf) {
44     IOBufQueue q_(IOBufQueue::cacheChainLength());
45     q_.append(std::move(buf));
46     ctx->fireRead(q_);
47
48     return makeFuture();
49   }
50 };
51
52 TEST(CodecTest, FixedLengthFrameDecoder) {
53   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
54   int called = 0;
55
56   pipeline
57     .addBack(FixedLengthFrameDecoder(10))
58     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
59         auto sz = buf->computeChainDataLength();
60         called++;
61         EXPECT_EQ(sz, 10);
62       }))
63     .finalize();
64
65   auto buf3 = IOBuf::create(3);
66   buf3->append(3);
67   auto buf11 = IOBuf::create(11);
68   buf11->append(11);
69   auto buf16 = IOBuf::create(16);
70   buf16->append(16);
71
72   IOBufQueue q(IOBufQueue::cacheChainLength());
73
74   q.append(std::move(buf3));
75   pipeline.read(q);
76   EXPECT_EQ(called, 0);
77
78   q.append(std::move(buf11));
79   pipeline.read(q);
80   EXPECT_EQ(called, 1);
81
82   q.append(std::move(buf16));
83   pipeline.read(q);
84   EXPECT_EQ(called, 3);
85 }
86
87 TEST(CodecTest, LengthFieldFramePipeline) {
88   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
89   int called = 0;
90
91   pipeline
92     .addBack(BytesReflector())
93     .addBack(LengthFieldBasedFrameDecoder())
94     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
95         auto sz = buf->computeChainDataLength();
96         called++;
97         EXPECT_EQ(sz, 2);
98       }))
99     .addBack(LengthFieldPrepender())
100     .finalize();
101
102   auto buf = IOBuf::create(2);
103   buf->append(2);
104   pipeline.write(std::move(buf));
105   EXPECT_EQ(called, 1);
106 }
107
108 TEST(CodecTest, LengthFieldFramePipelineLittleEndian) {
109   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
110   int called = 0;
111
112   pipeline
113     .addBack(BytesReflector())
114     .addBack(LengthFieldBasedFrameDecoder(4, 100, 0, 0, 4, false))
115     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
116         auto sz = buf->computeChainDataLength();
117         called++;
118         EXPECT_EQ(sz, 1);
119       }))
120     .addBack(LengthFieldPrepender(4, 0, false, false))
121     .finalize();
122
123   auto buf = IOBuf::create(1);
124   buf->append(1);
125   pipeline.write(std::move(buf));
126   EXPECT_EQ(called, 1);
127 }
128
129 TEST(CodecTest, LengthFieldFrameDecoderSimple) {
130   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
131   int called = 0;
132
133   pipeline
134     .addBack(LengthFieldBasedFrameDecoder())
135     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
136         auto sz = buf->computeChainDataLength();
137         called++;
138         EXPECT_EQ(sz, 1);
139       }))
140     .finalize();
141
142   auto bufFrame = IOBuf::create(4);
143   bufFrame->append(4);
144   RWPrivateCursor c(bufFrame.get());
145   c.writeBE((uint32_t)1);
146   auto bufData = IOBuf::create(1);
147   bufData->append(1);
148
149   IOBufQueue q(IOBufQueue::cacheChainLength());
150
151   q.append(std::move(bufFrame));
152   pipeline.read(q);
153   EXPECT_EQ(called, 0);
154
155   q.append(std::move(bufData));
156   pipeline.read(q);
157   EXPECT_EQ(called, 1);
158 }
159
160 TEST(CodecTest, LengthFieldFrameDecoderNoStrip) {
161   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
162   int called = 0;
163
164   pipeline
165     .addBack(LengthFieldBasedFrameDecoder(2, 10, 0, 0, 0))
166     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
167         auto sz = buf->computeChainDataLength();
168         called++;
169         EXPECT_EQ(sz, 3);
170       }))
171     .finalize();
172
173   auto bufFrame = IOBuf::create(2);
174   bufFrame->append(2);
175   RWPrivateCursor c(bufFrame.get());
176   c.writeBE((uint16_t)1);
177   auto bufData = IOBuf::create(1);
178   bufData->append(1);
179
180   IOBufQueue q(IOBufQueue::cacheChainLength());
181
182   q.append(std::move(bufFrame));
183   pipeline.read(q);
184   EXPECT_EQ(called, 0);
185
186   q.append(std::move(bufData));
187   pipeline.read(q);
188   EXPECT_EQ(called, 1);
189 }
190
191 TEST(CodecTest, LengthFieldFrameDecoderAdjustment) {
192   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
193   int called = 0;
194
195   pipeline
196     .addBack(LengthFieldBasedFrameDecoder(2, 10, 0, -2, 0))
197     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
198         auto sz = buf->computeChainDataLength();
199         called++;
200         EXPECT_EQ(sz, 3);
201       }))
202     .finalize();
203
204   auto bufFrame = IOBuf::create(2);
205   bufFrame->append(2);
206   RWPrivateCursor c(bufFrame.get());
207   c.writeBE((uint16_t)3); // includes frame size
208   auto bufData = IOBuf::create(1);
209   bufData->append(1);
210
211   IOBufQueue q(IOBufQueue::cacheChainLength());
212
213   q.append(std::move(bufFrame));
214   pipeline.read(q);
215   EXPECT_EQ(called, 0);
216
217   q.append(std::move(bufData));
218   pipeline.read(q);
219   EXPECT_EQ(called, 1);
220 }
221
222 TEST(CodecTest, LengthFieldFrameDecoderPreHeader) {
223   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
224   int called = 0;
225
226   pipeline
227     .addBack(LengthFieldBasedFrameDecoder(2, 10, 2, 0, 0))
228     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
229         auto sz = buf->computeChainDataLength();
230         called++;
231         EXPECT_EQ(sz, 5);
232       }))
233     .finalize();
234
235   auto bufFrame = IOBuf::create(4);
236   bufFrame->append(4);
237   RWPrivateCursor c(bufFrame.get());
238   c.write((uint16_t)100); // header
239   c.writeBE((uint16_t)1); // frame size
240   auto bufData = IOBuf::create(1);
241   bufData->append(1);
242
243   IOBufQueue q(IOBufQueue::cacheChainLength());
244
245   q.append(std::move(bufFrame));
246   pipeline.read(q);
247   EXPECT_EQ(called, 0);
248
249   q.append(std::move(bufData));
250   pipeline.read(q);
251   EXPECT_EQ(called, 1);
252 }
253
254 TEST(CodecTest, LengthFieldFrameDecoderPostHeader) {
255   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
256   int called = 0;
257
258   pipeline
259     .addBack(LengthFieldBasedFrameDecoder(2, 10, 0, 2, 0))
260     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
261         auto sz = buf->computeChainDataLength();
262         called++;
263         EXPECT_EQ(sz, 5);
264       }))
265     .finalize();
266
267   auto bufFrame = IOBuf::create(4);
268   bufFrame->append(4);
269   RWPrivateCursor c(bufFrame.get());
270   c.writeBE((uint16_t)1); // frame size
271   c.write((uint16_t)100); // header
272   auto bufData = IOBuf::create(1);
273   bufData->append(1);
274
275   IOBufQueue q(IOBufQueue::cacheChainLength());
276
277   q.append(std::move(bufFrame));
278   pipeline.read(q);
279   EXPECT_EQ(called, 0);
280
281   q.append(std::move(bufData));
282   pipeline.read(q);
283   EXPECT_EQ(called, 1);
284 }
285
286 TEST(CodecTest, LengthFieldFrameDecoderStripPrePostHeader) {
287   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
288   int called = 0;
289
290   pipeline
291     .addBack(LengthFieldBasedFrameDecoder(2, 10, 2, 2, 4))
292     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
293         auto sz = buf->computeChainDataLength();
294         called++;
295         EXPECT_EQ(sz, 3);
296       }))
297     .finalize();
298
299   auto bufFrame = IOBuf::create(6);
300   bufFrame->append(6);
301   RWPrivateCursor c(bufFrame.get());
302   c.write((uint16_t)100); // pre header
303   c.writeBE((uint16_t)1); // frame size
304   c.write((uint16_t)100); // post header
305   auto bufData = IOBuf::create(1);
306   bufData->append(1);
307
308   IOBufQueue q(IOBufQueue::cacheChainLength());
309
310   q.append(std::move(bufFrame));
311   pipeline.read(q);
312   EXPECT_EQ(called, 0);
313
314   q.append(std::move(bufData));
315   pipeline.read(q);
316   EXPECT_EQ(called, 1);
317 }
318
319 TEST(CodecTest, LengthFieldFrameDecoderStripPrePostHeaderFrameInclHeader) {
320   ChannelPipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
321   int called = 0;
322
323   pipeline
324     .addBack(LengthFieldBasedFrameDecoder(2, 10, 2, -2, 4))
325     .addBack(FrameTester([&](std::unique_ptr<IOBuf> buf) {
326         auto sz = buf->computeChainDataLength();
327         called++;
328         EXPECT_EQ(sz, 3);
329       }))
330     .finalize();
331
332   auto bufFrame = IOBuf::create(6);
333   bufFrame->append(6);
334   RWPrivateCursor c(bufFrame.get());
335   c.write((uint16_t)100); // pre header
336   c.writeBE((uint16_t)5); // frame size
337   c.write((uint16_t)100); // post header
338   auto bufData = IOBuf::create(1);
339   bufData->append(1);
340
341   IOBufQueue q(IOBufQueue::cacheChainLength());
342
343   q.append(std::move(bufFrame));
344   pipeline.read(q);
345   EXPECT_EQ(called, 0);
346
347   q.append(std::move(bufData));
348   pipeline.read(q);
349   EXPECT_EQ(called, 1);
350 }