blob: 9488091094f3f0db0a05c6a4ceef96bbd6e64c8d [file] [log] [blame]
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +09001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#define BOOST_TEST_MODULE TNonblockingServerTest
21#include <boost/test/unit_test.hpp>
22#include <boost/smart_ptr.hpp>
23
24#include "thrift/concurrency/Thread.h"
25#include "thrift/server/TNonblockingServer.h"
26
27#include "gen-cpp/ParentService.h"
28
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +090029#include <event.h>
30
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +090031using namespace apache::thrift;
32
33struct Handler : public test::ParentServiceIf {
34 void addString(const std::string& s) { strings_.push_back(s); }
35 void getStrings(std::vector<std::string>& _return) { _return = strings_; }
36 std::vector<std::string> strings_;
37
38 // dummy overrides not used in this test
39 int32_t incrementGeneration() { return 0; }
40 int32_t getGeneration() { return 0; }
41 void getDataWait(std::string&, int32_t) {}
42 void onewayWait() {}
43 void exceptionWait(const std::string&) {}
44 void unexpectedExceptionWait(const std::string&) {}
45};
46
47class Fixture {
48private:
Ben Craig7207c222015-07-06 08:40:35 -050049 struct Runner : public apache::thrift::concurrency::Runnable {
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +090050 boost::shared_ptr<server::TNonblockingServer> server;
51 bool error;
52 virtual void run() {
53 error = false;
54 try {
55 server->serve();
56 } catch (const TException& x) {
57 error = true;
58 }
59 }
60 };
61
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +090062 struct EventDeleter {
63 void operator()(event_base* p) { event_base_free(p); }
64 };
65
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +090066protected:
67 Fixture() : processor(new test::ParentServiceProcessor(boost::make_shared<Handler>())) {}
68
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +090069 ~Fixture() {
70 if (server) {
71 server->stop();
72 }
73 if (thread) {
74 thread->join();
75 }
76 }
77
78 void setEventBase(event_base* user_event_base) {
79 userEventBase_.reset(user_event_base, EventDeleter());
80 }
81
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +090082 int startServer(int port) {
Ben Craig7207c222015-07-06 08:40:35 -050083 boost::scoped_ptr<apache::thrift::concurrency::ThreadFactory> threadFactory(
84 new apache::thrift::concurrency::PlatformThreadFactory(
Nobuaki Sukegawa28256642014-12-16 03:24:37 +090085#if !USE_BOOST_THREAD && !USE_STD_THREAD
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +090086 concurrency::PlatformThreadFactory::OTHER,
87 concurrency::PlatformThreadFactory::NORMAL,
88 1,
89#endif
90 true));
91
92 int retry_count = port ? 10 : 0;
93 for (int p = port; p <= port + retry_count; p++) {
94 server.reset(new server::TNonblockingServer(processor, p));
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +090095 if (userEventBase_) {
96 try {
97 server->registerEvents(userEventBase_.get());
98 } catch (const TException& x) {
99 // retry with next port
100 continue;
101 }
102 }
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +0900103 boost::shared_ptr<Runner> runner(new Runner);
104 runner->server = server;
105 thread = threadFactory->newThread(runner);
106 thread->start();
107 // wait 50ms for the server to begin listening
108 THRIFT_SLEEP_USEC(50000);
109 if (!runner->error) {
110 return p;
111 }
112 }
113 throw transport::TTransportException(transport::TTransportException::NOT_OPEN,
114 "Failed to start server.");
115 }
116
117 bool canCommunicate(int serverPort) {
118 boost::shared_ptr<transport::TSocket> socket(new transport::TSocket("localhost", serverPort));
119 socket->open();
120 test::ParentServiceClient client(boost::make_shared<protocol::TBinaryProtocol>(
121 boost::make_shared<transport::TFramedTransport>(socket)));
122 client.addString("foo");
123 std::vector<std::string> strings;
124 client.getStrings(strings);
125 return strings.size() == 1 && !(strings[0].compare("foo"));
126 }
127
128private:
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +0900129 boost::shared_ptr<event_base> userEventBase_;
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +0900130 boost::shared_ptr<test::ParentServiceProcessor> processor;
Ben Craig7207c222015-07-06 08:40:35 -0500131 boost::shared_ptr<apache::thrift::concurrency::Thread> thread;
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +0900132
133protected:
134 boost::shared_ptr<server::TNonblockingServer> server;
135};
136
137BOOST_AUTO_TEST_SUITE(TNonblockingServerTest)
138
139BOOST_FIXTURE_TEST_CASE(get_specified_port, Fixture) {
140 int specified_port = startServer(12345);
141 BOOST_REQUIRE_GE(specified_port, 12345);
142 BOOST_REQUIRE_EQUAL(server->getListenPort(), specified_port);
143 BOOST_CHECK(canCommunicate(specified_port));
144
145 server->stop();
146 BOOST_CHECK_EQUAL(server->getListenPort(), specified_port);
147}
148
149BOOST_FIXTURE_TEST_CASE(get_assigned_port, Fixture) {
150 int specified_port = startServer(0);
151 BOOST_REQUIRE_EQUAL(specified_port, 0);
152 int assigned_port = server->getListenPort();
153 BOOST_REQUIRE_NE(assigned_port, 0);
154 BOOST_CHECK(canCommunicate(assigned_port));
155
156 server->stop();
157 BOOST_CHECK_EQUAL(server->getListenPort(), 0);
158}
159
Nobuaki Sukegawa8016af82015-01-02 23:14:22 +0900160BOOST_FIXTURE_TEST_CASE(provide_event_base, Fixture) {
161 event_base* eb = event_base_new();
162 setEventBase(eb);
163 startServer(0);
164
165 // assert that the server works
166 BOOST_CHECK(canCommunicate(server->getListenPort()));
167#if LIBEVENT_VERSION_NUMBER > 0x02010400
168 // also assert that the event_base is actually used when it's easy
169 BOOST_CHECK_GT(event_base_get_num_events(eb, EVENT_BASE_COUNT_ADDED), 0);
170#endif
171}
172
Nobuaki Sukegawad0d7a652014-12-07 21:36:51 +0900173BOOST_AUTO_TEST_SUITE_END()