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 std::unique_ptr<IOBuf> decode(Context* ctx,
39 class EchoService : public Service<std::string, std::string> {
41 Future<std::string> operator()(std::string req) override { return req; }
44 class EchoIntService : public Service<std::string, int> {
46 Future<int> operator()(std::string req) override {
47 return folly::to<int>(req);
51 template <typename Req, typename Resp>
52 class ServerPipelineFactory
53 : public PipelineFactory<ServicePipeline> {
56 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
57 newPipeline(std::shared_ptr<AsyncSocket> socket) override {
58 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
59 new ServicePipeline());
60 pipeline->addBack(AsyncSocketHandler(socket));
61 pipeline->addBack(SimpleDecode());
62 pipeline->addBack(StringCodec());
63 pipeline->addBack(SerialServerDispatcher<Req, Resp>(&service_));
72 template <typename Req, typename Resp>
73 class ClientPipelineFactory : public PipelineFactory<ServicePipeline> {
76 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
77 newPipeline(std::shared_ptr<AsyncSocket> socket) override {
78 std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
79 new ServicePipeline());
80 pipeline->addBack(AsyncSocketHandler(socket));
81 pipeline->addBack(SimpleDecode());
82 pipeline->addBack(StringCodec());
88 template <typename Pipeline, typename Req, typename Resp>
89 class ClientServiceFactory : public ServiceFactory<Pipeline, Req, Resp> {
91 class ClientService : public Service<Req, Resp> {
93 explicit ClientService(Pipeline* pipeline) {
94 dispatcher_.setPipeline(pipeline);
96 Future<Resp> operator()(Req request) override {
97 return dispatcher_(std::move(request));
100 SerialClientDispatcher<Pipeline, Req, Resp> dispatcher_;
103 Future<std::shared_ptr<Service<Req, Resp>>> operator() (
104 std::shared_ptr<ClientBootstrap<Pipeline>> client) override {
105 return Future<std::shared_ptr<Service<Req, Resp>>>(
106 std::make_shared<ClientService>(client->getPipeline()));
110 TEST(Wangle, ClientServerTest) {
114 ServerBootstrap<ServicePipeline> server;
115 server.childPipeline(
116 std::make_shared<ServerPipelineFactory<std::string, std::string>>());
120 auto client = std::make_shared<ClientBootstrap<ServicePipeline>>();
121 ClientServiceFactory<ServicePipeline, std::string, std::string> serviceFactory;
122 client->pipelineFactory(
123 std::make_shared<ClientPipelineFactory<std::string, std::string>>());
124 SocketAddress addr("127.0.0.1", port);
125 client->connect(addr);
126 auto service = serviceFactory(client).value();
127 auto rep = (*service)("test");
129 rep.then([&](std::string value) {
130 EXPECT_EQ("test", value);
131 EventBaseManager::get()->getEventBase()->terminateLoopSoon();
134 EventBaseManager::get()->getEventBase()->loopForever();
139 class AppendFilter : public ServiceFilter<std::string, std::string> {
141 explicit AppendFilter(
142 std::shared_ptr<Service<std::string, std::string>> service) :
143 ServiceFilter<std::string, std::string>(service) {}
145 Future<std::string> operator()(std::string req) override {
146 return (*service_)(req + "\n");
150 class IntToStringFilter
151 : public ServiceFilter<int, int, std::string, std::string> {
153 explicit IntToStringFilter(
154 std::shared_ptr<Service<std::string, std::string>> service) :
155 ServiceFilter<int, int, std::string, std::string>(service) {}
157 Future<int> operator()(int req) override {
158 return (*service_)(folly::to<std::string>(req)).then([](std::string resp) {
159 return folly::to<int>(resp);
164 TEST(Wangle, FilterTest) {
165 auto service = std::make_shared<EchoService>();
166 auto filter = std::make_shared<AppendFilter>(service);
167 auto result = (*filter)("test");
168 EXPECT_EQ(result.value(), "test\n");
171 TEST(Wangle, ComplexFilterTest) {
172 auto service = std::make_shared<EchoService>();
173 auto filter = std::make_shared<IntToStringFilter>(service);
174 auto result = (*filter)(1);
175 EXPECT_EQ(result.value(), 1);
178 class ChangeTypeFilter
179 : public ServiceFilter<int, std::string, std::string, int> {
181 explicit ChangeTypeFilter(
182 std::shared_ptr<Service<std::string, int>> service) :
183 ServiceFilter<int, std::string, std::string, int>(service) {}
185 Future<std::string> operator()(int req) override {
186 return (*service_)(folly::to<std::string>(req)).then([](int resp) {
187 return folly::to<std::string>(resp);
192 TEST(Wangle, SuperComplexFilterTest) {
193 auto service = std::make_shared<EchoIntService>();
194 auto filter = std::make_shared<ChangeTypeFilter>(service);
195 auto result = (*filter)(1);
196 EXPECT_EQ(result.value(), "1");
199 template <typename Pipeline, typename Req, typename Resp>
200 class ConnectionCountFilter : public ServiceFactoryFilter<Pipeline, Req, Resp> {
202 explicit ConnectionCountFilter(
203 std::shared_ptr<ServiceFactory<Pipeline, Req, Resp>> factory)
204 : ServiceFactoryFilter<Pipeline, Req, Resp>(factory) {}
206 Future<std::shared_ptr<Service<Req, Resp>>> operator()(
207 std::shared_ptr<ClientBootstrap<Pipeline>> client) override {
209 return (*this->serviceFactory_)(client);
212 int connectionCount{0};
215 TEST(Wangle, ServiceFactoryFilter) {
218 ClientServiceFactory<ServicePipeline, std::string, std::string>>();
219 auto countingFactory =
221 ConnectionCountFilter<ServicePipeline, std::string, std::string>>(
224 auto client = std::make_shared<ClientBootstrap<ServicePipeline>>();
226 client->pipelineFactory(
227 std::make_shared<ClientPipelineFactory<std::string, std::string>>());
228 // It doesn't matter if connect succeds or not, but it needs to be called
229 // to create a pipeline
230 client->connect(folly::SocketAddress("::1", 8090));
232 auto service = (*countingFactory)(client).value();
234 // After the first service goes away, the client can be reused
235 service = (*countingFactory)(client).value();
236 EXPECT_EQ(2, countingFactory->connectionCount);
239 TEST(Wangle, FactoryToService) {
241 std::make_shared<ConstFactory<ServicePipeline, std::string, std::string>>(
242 std::make_shared<EchoService>());
243 FactoryToService<ServicePipeline, std::string, std::string> service(
246 EXPECT_EQ("test", service("test").value());
249 int main(int argc, char** argv) {
250 testing::InitGoogleTest(&argc, argv);
251 google::InitGoogleLogging(argv[0]);
252 gflags::ParseCommandLineFlags(&argc, &argv, true);
254 return RUN_ALL_TESTS();