2 * Copyright 2015 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
26 using namespace folly;
27 using namespace folly::wangle;
28 using namespace testing;
30 typedef StrictMock<MockHandlerAdapter<int, int>> IntHandler;
31 class IntHandler2 : public StrictMock<MockHandlerAdapter<int, int>> {};
41 ACTION(FireReadException) {
42 arg0->fireReadException(arg1);
46 arg0->fireWrite(arg1);
53 // Test move only types, among other things
54 TEST(PipelineTest, RealHandlersCompile) {
56 auto socket = AsyncSocket::newSocket(&eb);
59 StaticPipeline<IOBufQueue&, std::unique_ptr<IOBuf>,
61 OutputBufferingHandler>
62 pipeline{AsyncSocketHandler(socket), OutputBufferingHandler()};
63 EXPECT_TRUE(pipeline.getHandler<AsyncSocketHandler>(0));
64 EXPECT_TRUE(pipeline.getHandler<OutputBufferingHandler>(1));
68 Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>> pipeline;
70 .addBack(AsyncSocketHandler(socket))
71 .addBack(OutputBufferingHandler())
73 EXPECT_TRUE(pipeline.getHandler<AsyncSocketHandler>(0));
74 EXPECT_TRUE(pipeline.getHandler<OutputBufferingHandler>(1));
78 // Test that handlers correctly fire the next handler when directed
79 TEST(PipelineTest, FireActions) {
85 EXPECT_CALL(handler2, attachPipeline(_));
86 EXPECT_CALL(handler1, attachPipeline(_));
89 StaticPipeline<int, int, IntHandler, IntHandler2>
90 pipeline(&handler1, &handler2);
92 EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
93 EXPECT_CALL(handler2, read_(_, _)).Times(1);
96 EXPECT_CALL(handler1, readEOF(_)).WillOnce(FireReadEOF());
97 EXPECT_CALL(handler2, readEOF(_)).Times(1);
100 EXPECT_CALL(handler1, readException(_, _)).WillOnce(FireReadException());
101 EXPECT_CALL(handler2, readException(_, _)).Times(1);
102 pipeline.readException(make_exception_wrapper<std::runtime_error>("blah"));
104 EXPECT_CALL(handler2, write_(_, _)).WillOnce(FireWrite());
105 EXPECT_CALL(handler1, write_(_, _)).Times(1);
106 EXPECT_NO_THROW(pipeline.write(1).value());
108 EXPECT_CALL(handler2, close_(_)).WillOnce(FireClose());
109 EXPECT_CALL(handler1, close_(_)).Times(1);
110 EXPECT_NO_THROW(pipeline.close().value());
114 EXPECT_CALL(handler1, detachPipeline(_));
115 EXPECT_CALL(handler2, detachPipeline(_));
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) {
123 EXPECT_CALL(handler, attachPipeline(_));
124 StaticPipeline<int, int, IntHandler>
127 EXPECT_CALL(handler, read_(_, _)).WillOnce(FireRead());
130 EXPECT_CALL(handler, readEOF(_)).WillOnce(FireReadEOF());
133 EXPECT_CALL(handler, readException(_, _)).WillOnce(FireReadException());
134 pipeline.readException(make_exception_wrapper<std::runtime_error>("blah"));
136 EXPECT_CALL(handler, write_(_, _)).WillOnce(FireWrite());
137 EXPECT_NO_THROW(pipeline.write(1).value());
139 EXPECT_CALL(handler, close_(_)).WillOnce(FireClose());
140 EXPECT_NO_THROW(pipeline.close().value());
142 EXPECT_CALL(handler, detachPipeline(_));
145 // Test having the last read handler turn around and write
146 TEST(PipelineTest, TurnAround) {
148 IntHandler2 handler2;
152 EXPECT_CALL(handler2, attachPipeline(_));
153 EXPECT_CALL(handler1, attachPipeline(_));
156 StaticPipeline<int, int, IntHandler, IntHandler2>
157 pipeline(&handler1, &handler2);
159 EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
160 EXPECT_CALL(handler2, read_(_, _)).WillOnce(FireWrite());
161 EXPECT_CALL(handler1, write_(_, _)).Times(1);
166 EXPECT_CALL(handler1, detachPipeline(_));
167 EXPECT_CALL(handler2, detachPipeline(_));
171 TEST(PipelineTest, DynamicFireActions) {
172 IntHandler handler1, handler2, handler3;
173 EXPECT_CALL(handler2, attachPipeline(_));
174 StaticPipeline<int, int, IntHandler>
179 EXPECT_CALL(handler3, attachPipeline(_));
180 EXPECT_CALL(handler1, attachPipeline(_));
188 EXPECT_TRUE(pipeline.getHandler<IntHandler>(0));
189 EXPECT_TRUE(pipeline.getHandler<IntHandler>(1));
190 EXPECT_TRUE(pipeline.getHandler<IntHandler>(2));
192 EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
193 EXPECT_CALL(handler2, read_(_, _)).WillOnce(FireRead());
194 EXPECT_CALL(handler3, read_(_, _)).Times(1);
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());
204 EXPECT_CALL(handler1, detachPipeline(_));
205 EXPECT_CALL(handler2, detachPipeline(_));
206 EXPECT_CALL(handler3, detachPipeline(_));
210 TEST(PipelineTest, DynamicAttachDetachOrder) {
211 IntHandler handler1, handler2;
212 Pipeline<int, int> pipeline;
215 EXPECT_CALL(handler2, attachPipeline(_));
216 EXPECT_CALL(handler1, attachPipeline(_));
224 EXPECT_CALL(handler1, detachPipeline(_));
225 EXPECT_CALL(handler2, detachPipeline(_));
229 TEST(PipelineTest, GetContext) {
231 EXPECT_CALL(handler, attachPipeline(_));
232 StaticPipeline<int, int, IntHandler> pipeline(&handler);
233 EXPECT_TRUE(handler.getContext());
234 EXPECT_CALL(handler, detachPipeline(_));
237 TEST(PipelineTest, HandlerInMultiplePipelines) {
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);
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);
253 EXPECT_FALSE(handler->getContext());
254 EXPECT_CALL(*handler, detachPipeline(_)).Times(2);
257 TEST(PipelineTest, NoDetachOnOwner) {
259 EXPECT_CALL(handler, attachPipeline(_));
260 StaticPipeline<int, int, IntHandler> pipeline(&handler);
261 pipeline.setOwner(&handler);
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;
268 void read(Context* ctx, Rin msg) {}
269 Future<void> write(Context* ctx, Win msg) { return makeFuture(); }
272 typedef HandlerAdapter<std::string, std::string> StringHandler;
273 typedef ConcreteHandler<int, std::string> IntToStringHandler;
274 typedef ConcreteHandler<std::string, int> StringToIntHandler;
276 TEST(Pipeline, MissingInboundOrOutbound) {
277 Pipeline<int, int> pipeline;
279 .addBack(HandlerAdapter<std::string, std::string>{})
281 EXPECT_THROW(pipeline.read(0), std::invalid_argument);
282 EXPECT_THROW(pipeline.readEOF(), std::invalid_argument);
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);
290 TEST(Pipeline, DynamicConstruction) {
292 Pipeline<std::string, std::string> pipeline;
293 pipeline.addBack(StringHandler());
294 pipeline.addBack(StringHandler());
296 // Exercise both addFront and addBack. Final pipeline is
297 // StI <-> ItS <-> StS <-> StS <-> StI <-> ItS
300 .addFront(IntToStringHandler{})
301 .addFront(StringToIntHandler{})
302 .addBack(StringToIntHandler{})
303 .addBack(IntToStringHandler{})