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.
16 #include <gtest/gtest.h>
18 #include <folly/wangle/codec/StringCodec.h>
19 #include <folly/wangle/codec/ByteToMessageCodec.h>
20 #include <folly/wangle/service/ClientDispatcher.h>
21 #include <folly/wangle/service/ServerDispatcher.h>
22 #include <folly/wangle/service/Service.h>
26 using namespace wangle;
28 typedef Pipeline<IOBufQueue&, std::string> ServicePipeline;
30 class SimpleDecode : public ByteToMessageCodec {
32 virtual std::unique_ptr<IOBuf> decode(
33 Context* ctx, IOBufQueue& buf, size_t&) {
38 class EchoService : public Service<std::string, std::string> {
40 virtual Future<std::string> operator()(std::string req) override {
45 class EchoIntService : public Service<std::string, int> {
47 virtual Future<int> operator()(std::string req) override {
48 return folly::to<int>(req);
52 template <typename Req, typename Resp>
53 class ServerPipelineFactory
54 : public PipelineFactory<ServicePipeline> {
57 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
58 newPipeline(std::shared_ptr<AsyncSocket> socket) override {
59 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
60 new ServicePipeline());
61 pipeline->addBack(AsyncSocketHandler(socket));
62 pipeline->addBack(SimpleDecode());
63 pipeline->addBack(StringCodec());
64 pipeline->addBack(SerialServerDispatcher<Req, Resp>(&service_));
73 template <typename Req, typename Resp>
74 class ClientPipelineFactory : public PipelineFactory<ServicePipeline> {
77 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
78 newPipeline(std::shared_ptr<AsyncSocket> socket) override {
79 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
80 new ServicePipeline());
81 pipeline->addBack(AsyncSocketHandler(socket));
82 pipeline->addBack(SimpleDecode());
83 pipeline->addBack(StringCodec());
89 template <typename Pipeline, typename Req, typename Resp>
90 class ClientServiceFactory : public ServiceFactory<Pipeline, Req, Resp> {
92 class ClientService : public Service<Req, Resp> {
94 explicit ClientService(Pipeline* pipeline) {
95 dispatcher_.setPipeline(pipeline);
97 Future<Resp> operator()(Req request) override {
98 return dispatcher_(std::move(request));
101 SerialClientDispatcher<Pipeline, Req, Resp> dispatcher_;
104 Future<std::shared_ptr<Service<Req, Resp>>> operator() (
105 std::shared_ptr<ClientBootstrap<Pipeline>> client) override {
106 return Future<std::shared_ptr<Service<Req, Resp>>>(
107 std::make_shared<ClientService>(client->getPipeline()));
111 TEST(Wangle, ClientServerTest) {
115 ServerBootstrap<ServicePipeline> server;
116 server.childPipeline(
117 std::make_shared<ServerPipelineFactory<std::string, std::string>>());
121 auto client = std::make_shared<ClientBootstrap<ServicePipeline>>();
122 ClientServiceFactory<ServicePipeline, std::string, std::string> serviceFactory;
123 client->pipelineFactory(
124 std::make_shared<ClientPipelineFactory<std::string, std::string>>());
125 SocketAddress addr("127.0.0.1", port);
126 client->connect(addr);
127 auto service = serviceFactory(client).value();
128 auto rep = (*service)("test");
130 rep.then([&](std::string value) {
131 EXPECT_EQ("test", value);
132 EventBaseManager::get()->getEventBase()->terminateLoopSoon();
135 EventBaseManager::get()->getEventBase()->loopForever();
140 class AppendFilter : public ServiceFilter<std::string, std::string> {
142 explicit AppendFilter(
143 std::shared_ptr<Service<std::string, std::string>> service) :
144 ServiceFilter<std::string, std::string>(service) {}
146 virtual Future<std::string> operator()(std::string req) {
147 return (*service_)(req + "\n");
151 class IntToStringFilter
152 : public ServiceFilter<int, int, std::string, std::string> {
154 explicit IntToStringFilter(
155 std::shared_ptr<Service<std::string, std::string>> service) :
156 ServiceFilter<int, int, std::string, std::string>(service) {}
158 virtual Future<int> operator()(int req) {
159 return (*service_)(folly::to<std::string>(req)).then([](std::string resp) {
160 return folly::to<int>(resp);
165 TEST(Wangle, FilterTest) {
166 auto service = std::make_shared<EchoService>();
167 auto filter = std::make_shared<AppendFilter>(service);
168 auto result = (*filter)("test");
169 EXPECT_EQ(result.value(), "test\n");
172 TEST(Wangle, ComplexFilterTest) {
173 auto service = std::make_shared<EchoService>();
174 auto filter = std::make_shared<IntToStringFilter>(service);
175 auto result = (*filter)(1);
176 EXPECT_EQ(result.value(), 1);
179 class ChangeTypeFilter
180 : public ServiceFilter<int, std::string, std::string, int> {
182 explicit ChangeTypeFilter(
183 std::shared_ptr<Service<std::string, int>> service) :
184 ServiceFilter<int, std::string, std::string, int>(service) {}
186 virtual Future<std::string> operator()(int req) {
187 return (*service_)(folly::to<std::string>(req)).then([](int resp) {
188 return folly::to<std::string>(resp);
193 TEST(Wangle, SuperComplexFilterTest) {
194 auto service = std::make_shared<EchoIntService>();
195 auto filter = std::make_shared<ChangeTypeFilter>(service);
196 auto result = (*filter)(1);
197 EXPECT_EQ(result.value(), "1");
200 template <typename Pipeline, typename Req, typename Resp>
201 class ConnectionCountFilter : public ServiceFactoryFilter<Pipeline, Req, Resp> {
203 explicit ConnectionCountFilter(
204 std::shared_ptr<ServiceFactory<Pipeline, Req, Resp>> factory)
205 : ServiceFactoryFilter<Pipeline, Req, Resp>(factory) {}
207 virtual Future<std::shared_ptr<Service<Req, Resp>>> operator()(
208 std::shared_ptr<ClientBootstrap<Pipeline>> client) {
210 return (*this->serviceFactory_)(client);
213 int connectionCount{0};
216 TEST(Wangle, ServiceFactoryFilter) {
219 ClientServiceFactory<ServicePipeline, std::string, std::string>>();
220 auto countingFactory =
222 ConnectionCountFilter<ServicePipeline, std::string, std::string>>(
225 auto client = std::make_shared<ClientBootstrap<ServicePipeline>>();
227 client->pipelineFactory(
228 std::make_shared<ClientPipelineFactory<std::string, std::string>>());
229 // It doesn't matter if connect succeds or not, but it needs to be called
230 // to create a pipeline
231 client->connect(folly::SocketAddress("::1", 8090));
233 auto service = (*countingFactory)(client).value();
235 // After the first service goes away, the client can be reused
236 service = (*countingFactory)(client).value();
237 EXPECT_EQ(2, countingFactory->connectionCount);
240 TEST(Wangle, FactoryToService) {
242 std::make_shared<ConstFactory<ServicePipeline, std::string, std::string>>(
243 std::make_shared<EchoService>());
244 FactoryToService<ServicePipeline, std::string, std::string> service(
247 EXPECT_EQ("test", service("test").value());
250 int main(int argc, char** argv) {
251 testing::InitGoogleTest(&argc, argv);
252 google::InitGoogleLogging(argv[0]);
253 gflags::ParseCommandLineFlags(&argc, &argv, true);
255 return RUN_ALL_TESTS();