36c4cee671b1aec9cf30e12f8ed3086fe41c187f
[folly.git] / folly / wangle / channel / test / PipelineTest.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/wangle/channel/Handler.h>
18 #include <folly/wangle/channel/Pipeline.h>
19 #include <folly/wangle/channel/StaticPipeline.h>
20 #include <folly/wangle/channel/AsyncSocketHandler.h>
21 #include <folly/wangle/channel/OutputBufferingHandler.h>
22 #include <folly/wangle/channel/test/MockHandler.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25
26 using namespace folly;
27 using namespace folly::wangle;
28 using namespace testing;
29
30 typedef StrictMock<MockHandlerAdapter<int, int>> IntHandler;
31 class IntHandler2 : public StrictMock<MockHandlerAdapter<int, int>> {};
32
33 ACTION(FireRead) {
34   arg0->fireRead(arg1);
35 }
36
37 ACTION(FireReadEOF) {
38   arg0->fireReadEOF();
39 }
40
41 ACTION(FireReadException) {
42   arg0->fireReadException(arg1);
43 }
44
45 ACTION(FireWrite) {
46   arg0->fireWrite(arg1);
47 }
48
49 ACTION(FireClose) {
50   arg0->fireClose();
51 }
52
53 // Test move only types, among other things
54 TEST(PipelineTest, RealHandlersCompile) {
55   EventBase eb;
56   auto socket = AsyncSocket::newSocket(&eb);
57   // static
58   {
59     StaticPipeline<IOBufQueue&, std::unique_ptr<IOBuf>,
60       AsyncSocketHandler,
61       OutputBufferingHandler>
62     pipeline{AsyncSocketHandler(socket), OutputBufferingHandler()};
63     EXPECT_TRUE(pipeline.getHandler<AsyncSocketHandler>(0));
64     EXPECT_TRUE(pipeline.getHandler<OutputBufferingHandler>(1));
65   }
66   // dynamic
67   {
68     Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
69     pipeline
70       .addBack(AsyncSocketHandler(socket))
71       .addBack(OutputBufferingHandler())
72       .finalize();
73     EXPECT_TRUE(pipeline.getHandler<AsyncSocketHandler>(0));
74     EXPECT_TRUE(pipeline.getHandler<OutputBufferingHandler>(1));
75   }
76 }
77
78 // Test that handlers correctly fire the next handler when directed
79 TEST(PipelineTest, FireActions) {
80   IntHandler handler1;
81   IntHandler2 handler2;
82
83   {
84     InSequence sequence;
85     EXPECT_CALL(handler2, attachPipeline(_));
86     EXPECT_CALL(handler1, attachPipeline(_));
87   }
88
89   StaticPipeline<int, int, IntHandler, IntHandler2>
90   pipeline(&handler1, &handler2);
91
92   EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
93   EXPECT_CALL(handler2, read_(_, _)).Times(1);
94   pipeline.read(1);
95
96   EXPECT_CALL(handler1, readEOF(_)).WillOnce(FireReadEOF());
97   EXPECT_CALL(handler2, readEOF(_)).Times(1);
98   pipeline.readEOF();
99
100   EXPECT_CALL(handler1, readException(_, _)).WillOnce(FireReadException());
101   EXPECT_CALL(handler2, readException(_, _)).Times(1);
102   pipeline.readException(make_exception_wrapper<std::runtime_error>("blah"));
103
104   EXPECT_CALL(handler2, write_(_, _)).WillOnce(FireWrite());
105   EXPECT_CALL(handler1, write_(_, _)).Times(1);
106   EXPECT_NO_THROW(pipeline.write(1).value());
107
108   EXPECT_CALL(handler2, close_(_)).WillOnce(FireClose());
109   EXPECT_CALL(handler1, close_(_)).Times(1);
110   EXPECT_NO_THROW(pipeline.close().value());
111
112   {
113     InSequence sequence;
114     EXPECT_CALL(handler1, detachPipeline(_));
115     EXPECT_CALL(handler2, detachPipeline(_));
116   }
117 }
118
119 // Test that nothing bad happens when actions reach the end of the pipeline
120 // (a warning will be logged, however)
121 TEST(PipelineTest, ReachEndOfPipeline) {
122   IntHandler handler;
123   EXPECT_CALL(handler, attachPipeline(_));
124   StaticPipeline<int, int, IntHandler>
125   pipeline(&handler);
126
127   EXPECT_CALL(handler, read_(_, _)).WillOnce(FireRead());
128   pipeline.read(1);
129
130   EXPECT_CALL(handler, readEOF(_)).WillOnce(FireReadEOF());
131   pipeline.readEOF();
132
133   EXPECT_CALL(handler, readException(_, _)).WillOnce(FireReadException());
134   pipeline.readException(make_exception_wrapper<std::runtime_error>("blah"));
135
136   EXPECT_CALL(handler, write_(_, _)).WillOnce(FireWrite());
137   EXPECT_NO_THROW(pipeline.write(1).value());
138
139   EXPECT_CALL(handler, close_(_)).WillOnce(FireClose());
140   EXPECT_NO_THROW(pipeline.close().value());
141
142   EXPECT_CALL(handler, detachPipeline(_));
143 }
144
145 // Test having the last read handler turn around and write
146 TEST(PipelineTest, TurnAround) {
147   IntHandler handler1;
148   IntHandler2 handler2;
149
150   {
151     InSequence sequence;
152     EXPECT_CALL(handler2, attachPipeline(_));
153     EXPECT_CALL(handler1, attachPipeline(_));
154   }
155
156   StaticPipeline<int, int, IntHandler, IntHandler2>
157   pipeline(&handler1, &handler2);
158
159   EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
160   EXPECT_CALL(handler2, read_(_, _)).WillOnce(FireWrite());
161   EXPECT_CALL(handler1, write_(_, _)).Times(1);
162   pipeline.read(1);
163
164   {
165     InSequence sequence;
166     EXPECT_CALL(handler1, detachPipeline(_));
167     EXPECT_CALL(handler2, detachPipeline(_));
168   }
169 }
170
171 TEST(PipelineTest, DynamicFireActions) {
172   IntHandler handler1, handler2, handler3;
173   EXPECT_CALL(handler2, attachPipeline(_));
174   StaticPipeline<int, int, IntHandler>
175   pipeline(&handler2);
176
177   {
178     InSequence sequence;
179     EXPECT_CALL(handler3, attachPipeline(_));
180     EXPECT_CALL(handler1, attachPipeline(_));
181   }
182
183   pipeline
184     .addFront(&handler1)
185     .addBack(&handler3)
186     .finalize();
187
188   EXPECT_TRUE(pipeline.getHandler<IntHandler>(0));
189   EXPECT_TRUE(pipeline.getHandler<IntHandler>(1));
190   EXPECT_TRUE(pipeline.getHandler<IntHandler>(2));
191
192   EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
193   EXPECT_CALL(handler2, read_(_, _)).WillOnce(FireRead());
194   EXPECT_CALL(handler3, read_(_, _)).Times(1);
195   pipeline.read(1);
196
197   EXPECT_CALL(handler3, write_(_, _)).WillOnce(FireWrite());
198   EXPECT_CALL(handler2, write_(_, _)).WillOnce(FireWrite());
199   EXPECT_CALL(handler1, write_(_, _)).Times(1);
200   EXPECT_NO_THROW(pipeline.write(1).value());
201
202   {
203     InSequence sequence;
204     EXPECT_CALL(handler1, detachPipeline(_));
205     EXPECT_CALL(handler2, detachPipeline(_));
206     EXPECT_CALL(handler3, detachPipeline(_));
207   }
208 }
209
210 TEST(PipelineTest, DynamicAttachDetachOrder) {
211   IntHandler handler1, handler2;
212   Pipeline<int, int> pipeline;
213   {
214     InSequence sequence;
215     EXPECT_CALL(handler2, attachPipeline(_));
216     EXPECT_CALL(handler1, attachPipeline(_));
217   }
218   pipeline
219     .addBack(&handler1)
220     .addBack(&handler2)
221     .finalize();
222   {
223     InSequence sequence;
224     EXPECT_CALL(handler1, detachPipeline(_));
225     EXPECT_CALL(handler2, detachPipeline(_));
226   }
227 }
228
229 TEST(PipelineTest, GetContext) {
230   IntHandler handler;
231   EXPECT_CALL(handler, attachPipeline(_));
232   StaticPipeline<int, int, IntHandler> pipeline(&handler);
233   EXPECT_TRUE(handler.getContext());
234   EXPECT_CALL(handler, detachPipeline(_));
235 }
236
237 TEST(PipelineTest, HandlerInMultiplePipelines) {
238   IntHandler handler;
239   EXPECT_CALL(handler, attachPipeline(_)).Times(2);
240   StaticPipeline<int, int, IntHandler> pipeline1(&handler);
241   StaticPipeline<int, int, IntHandler> pipeline2(&handler);
242   EXPECT_FALSE(handler.getContext());
243   EXPECT_CALL(handler, detachPipeline(_)).Times(2);
244 }
245
246 TEST(PipelineTest, HandlerInPipelineTwice) {
247   auto handler = std::make_shared<IntHandler>();
248   EXPECT_CALL(*handler, attachPipeline(_)).Times(2);
249   Pipeline<int, int> pipeline;
250   pipeline.addBack(handler);
251   pipeline.addBack(handler);
252   pipeline.finalize();
253   EXPECT_FALSE(handler->getContext());
254   EXPECT_CALL(*handler, detachPipeline(_)).Times(2);
255 }
256
257 TEST(PipelineTest, NoDetachOnOwner) {
258   IntHandler handler;
259   EXPECT_CALL(handler, attachPipeline(_));
260   StaticPipeline<int, int, IntHandler> pipeline(&handler);
261   pipeline.setOwner(&handler);
262 }
263
264 template <class Rin, class Rout = Rin, class Win = Rout, class Wout = Rin>
265 class ConcreteHandler : public Handler<Rin, Rout, Win, Wout> {
266   typedef typename Handler<Rin, Rout, Win, Wout>::Context Context;
267  public:
268   void read(Context* ctx, Rin msg) {}
269   Future<void> write(Context* ctx, Win msg) { return makeFuture(); }
270 };
271
272 typedef HandlerAdapter<std::string, std::string> StringHandler;
273 typedef ConcreteHandler<int, std::string> IntToStringHandler;
274 typedef ConcreteHandler<std::string, int> StringToIntHandler;
275
276 TEST(Pipeline, MissingInboundOrOutbound) {
277   Pipeline<int, int> pipeline;
278   pipeline
279     .addBack(HandlerAdapter<std::string, std::string>{})
280     .finalize();
281   EXPECT_THROW(pipeline.read(0), std::invalid_argument);
282   EXPECT_THROW(pipeline.readEOF(), std::invalid_argument);
283   EXPECT_THROW(
284       pipeline.readException(exception_wrapper(std::runtime_error("blah"))),
285       std::invalid_argument);
286   EXPECT_THROW(pipeline.write(0), std::invalid_argument);
287   EXPECT_THROW(pipeline.close(), std::invalid_argument);
288 }
289
290 TEST(Pipeline, DynamicConstruction) {
291   {
292     Pipeline<std::string, std::string> pipeline;
293     pipeline.addBack(StringHandler());
294     pipeline.addBack(StringHandler());
295
296     // Exercise both addFront and addBack. Final pipeline is
297     // StI <-> ItS <-> StS <-> StS <-> StI <-> ItS
298     EXPECT_NO_THROW(
299       pipeline
300         .addFront(IntToStringHandler{})
301         .addFront(StringToIntHandler{})
302         .addBack(StringToIntHandler{})
303         .addBack(IntToStringHandler{})
304         .finalize());
305   }
306 }
307
308 TEST(Pipeline, RemovePointer) {
309   IntHandler handler1, handler2;
310   EXPECT_CALL(handler1, attachPipeline(_));
311   EXPECT_CALL(handler2, attachPipeline(_));
312   Pipeline<int, int> pipeline;
313   pipeline
314     .addBack(&handler1)
315     .addBack(&handler2)
316     .finalize();
317
318   EXPECT_CALL(handler1, detachPipeline(_));
319   pipeline
320     .remove(&handler1)
321     .finalize();
322
323   EXPECT_CALL(handler2, read_(_, _));
324   pipeline.read(1);
325
326   EXPECT_CALL(handler2, detachPipeline(_));
327 }
328
329 TEST(Pipeline, RemoveFront) {
330   IntHandler handler1, handler2;
331   EXPECT_CALL(handler1, attachPipeline(_));
332   EXPECT_CALL(handler2, attachPipeline(_));
333   Pipeline<int, int> pipeline;
334   pipeline
335     .addBack(&handler1)
336     .addBack(&handler2)
337     .finalize();
338
339   EXPECT_CALL(handler1, detachPipeline(_));
340   pipeline
341     .removeFront()
342     .finalize();
343
344   EXPECT_CALL(handler2, read_(_, _));
345   pipeline.read(1);
346
347   EXPECT_CALL(handler2, detachPipeline(_));
348 }
349
350 TEST(Pipeline, RemoveBack) {
351   IntHandler handler1, handler2;
352   EXPECT_CALL(handler1, attachPipeline(_));
353   EXPECT_CALL(handler2, attachPipeline(_));
354   Pipeline<int, int> pipeline;
355   pipeline
356     .addBack(&handler1)
357     .addBack(&handler2)
358     .finalize();
359
360   EXPECT_CALL(handler2, detachPipeline(_));
361   pipeline
362     .removeBack()
363     .finalize();
364
365   EXPECT_CALL(handler1, read_(_, _));
366   pipeline.read(1);
367
368   EXPECT_CALL(handler1, detachPipeline(_));
369 }
370
371 TEST(Pipeline, RemoveType) {
372   IntHandler handler1;
373   IntHandler2 handler2;
374   EXPECT_CALL(handler1, attachPipeline(_));
375   EXPECT_CALL(handler2, attachPipeline(_));
376   Pipeline<int, int> pipeline;
377   pipeline
378     .addBack(&handler1)
379     .addBack(&handler2)
380     .finalize();
381
382   EXPECT_CALL(handler1, detachPipeline(_));
383   pipeline
384     .remove<IntHandler>()
385     .finalize();
386
387   EXPECT_CALL(handler2, read_(_, _));
388   pipeline.read(1);
389
390   EXPECT_CALL(handler2, detachPipeline(_));
391 }