1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <thread>
20
21 #include <gtest/gtest.h>
22
23 #include "absl/memory/memory.h"
24
25 #include <grpc/grpc.h>
26 #include <grpcpp/channel.h>
27 #include <grpcpp/client_context.h>
28 #include <grpcpp/create_channel.h>
29 #include <grpcpp/impl/server_builder_option.h>
30 #include <grpcpp/impl/server_builder_plugin.h>
31 #include <grpcpp/impl/server_initializer.h>
32 #include <grpcpp/security/credentials.h>
33 #include <grpcpp/security/server_credentials.h>
34 #include <grpcpp/server.h>
35 #include <grpcpp/server_builder.h>
36 #include <grpcpp/server_context.h>
37
38 #include "src/proto/grpc/testing/echo.grpc.pb.h"
39 #include "test/core/util/port.h"
40 #include "test/core/util/test_config.h"
41 #include "test/cpp/end2end/test_service_impl.h"
42
43 #define PLUGIN_NAME "TestServerBuilderPlugin"
44
45 namespace grpc {
46 namespace testing {
47
48 class TestServerBuilderPlugin : public ServerBuilderPlugin {
49 public:
TestServerBuilderPlugin()50 TestServerBuilderPlugin() : service_(new TestServiceImpl()) {
51 init_server_is_called_ = false;
52 finish_is_called_ = false;
53 change_arguments_is_called_ = false;
54 register_service_ = false;
55 }
56
name()57 std::string name() override { return PLUGIN_NAME; }
58
InitServer(ServerInitializer * si)59 void InitServer(ServerInitializer* si) override {
60 init_server_is_called_ = true;
61 if (register_service_) {
62 si->RegisterService(service_);
63 }
64 }
65
Finish(ServerInitializer *)66 void Finish(ServerInitializer* /*si*/) override { finish_is_called_ = true; }
67
ChangeArguments(const std::string &,void *)68 void ChangeArguments(const std::string& /*name*/, void* /*value*/) override {
69 change_arguments_is_called_ = true;
70 }
71
has_async_methods() const72 bool has_async_methods() const override {
73 if (register_service_) {
74 return service_->has_async_methods();
75 }
76 return false;
77 }
78
has_sync_methods() const79 bool has_sync_methods() const override {
80 if (register_service_) {
81 return service_->has_synchronous_methods();
82 }
83 return false;
84 }
85
SetRegisterService()86 void SetRegisterService() { register_service_ = true; }
87
init_server_is_called()88 bool init_server_is_called() { return init_server_is_called_; }
finish_is_called()89 bool finish_is_called() { return finish_is_called_; }
change_arguments_is_called()90 bool change_arguments_is_called() { return change_arguments_is_called_; }
91
92 private:
93 bool init_server_is_called_;
94 bool finish_is_called_;
95 bool change_arguments_is_called_;
96 bool register_service_;
97 std::shared_ptr<TestServiceImpl> service_;
98 };
99
100 class InsertPluginServerBuilderOption : public ServerBuilderOption {
101 public:
InsertPluginServerBuilderOption()102 InsertPluginServerBuilderOption() { register_service_ = false; }
103
UpdateArguments(ChannelArguments *)104 void UpdateArguments(ChannelArguments* /*arg*/) override {}
105
UpdatePlugins(std::vector<std::unique_ptr<ServerBuilderPlugin>> * plugins)106 void UpdatePlugins(
107 std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) override {
108 plugins->clear();
109
110 std::unique_ptr<TestServerBuilderPlugin> plugin(
111 new TestServerBuilderPlugin());
112 if (register_service_) plugin->SetRegisterService();
113 plugins->emplace_back(std::move(plugin));
114 }
115
SetRegisterService()116 void SetRegisterService() { register_service_ = true; }
117
118 private:
119 bool register_service_;
120 };
121
CreateTestServerBuilderPlugin()122 std::unique_ptr<ServerBuilderPlugin> CreateTestServerBuilderPlugin() {
123 return std::unique_ptr<ServerBuilderPlugin>(new TestServerBuilderPlugin());
124 }
125
126 // Force AddServerBuilderPlugin() to be called at static initialization time.
127 struct StaticTestPluginInitializer {
StaticTestPluginInitializergrpc::testing::StaticTestPluginInitializer128 StaticTestPluginInitializer() {
129 grpc::ServerBuilder::InternalAddPluginFactory(
130 &CreateTestServerBuilderPlugin);
131 }
132 } static_plugin_initializer_test_;
133
134 // When the param boolean is true, the ServerBuilder plugin will be added at the
135 // time of static initialization. When it's false, the ServerBuilder plugin will
136 // be added using ServerBuilder::SetOption().
137 class ServerBuilderPluginTest : public ::testing::TestWithParam<bool> {
138 public:
ServerBuilderPluginTest()139 ServerBuilderPluginTest() {}
140
SetUp()141 void SetUp() override {
142 port_ = grpc_pick_unused_port_or_die();
143 builder_ = std::make_unique<ServerBuilder>();
144 }
145
InsertPlugin()146 void InsertPlugin() {
147 if (GetParam()) {
148 // Add ServerBuilder plugin in static initialization
149 CheckPresent();
150 } else {
151 // Add ServerBuilder plugin using ServerBuilder::SetOption()
152 builder_->SetOption(std::unique_ptr<ServerBuilderOption>(
153 new InsertPluginServerBuilderOption()));
154 }
155 }
156
InsertPluginWithTestService()157 void InsertPluginWithTestService() {
158 if (GetParam()) {
159 // Add ServerBuilder plugin in static initialization
160 auto plugin = CheckPresent();
161 EXPECT_TRUE(plugin);
162 plugin->SetRegisterService();
163 } else {
164 // Add ServerBuilder plugin using ServerBuilder::SetOption()
165 std::unique_ptr<InsertPluginServerBuilderOption> option(
166 new InsertPluginServerBuilderOption());
167 option->SetRegisterService();
168 builder_->SetOption(std::move(option));
169 }
170 }
171
StartServer()172 void StartServer() {
173 std::string server_address = "localhost:" + to_string(port_);
174 builder_->AddListeningPort(server_address, InsecureServerCredentials());
175 // we run some tests without a service, and for those we need to supply a
176 // frequently polled completion queue
177 cq_ = builder_->AddCompletionQueue();
178 cq_thread_ = new std::thread(&ServerBuilderPluginTest::RunCQ, this);
179 server_ = builder_->BuildAndStart();
180 EXPECT_TRUE(CheckPresent());
181 }
182
ResetStub()183 void ResetStub() {
184 string target = "dns:localhost:" + to_string(port_);
185 channel_ = grpc::CreateChannel(target, InsecureChannelCredentials());
186 stub_ = grpc::testing::EchoTestService::NewStub(channel_);
187 }
188
TearDown()189 void TearDown() override {
190 auto plugin = CheckPresent();
191 EXPECT_TRUE(plugin);
192 EXPECT_TRUE(plugin->init_server_is_called());
193 EXPECT_TRUE(plugin->finish_is_called());
194 server_->Shutdown();
195 cq_->Shutdown();
196 cq_thread_->join();
197 delete cq_thread_;
198 }
199
to_string(const int number)200 string to_string(const int number) {
201 std::stringstream strs;
202 strs << number;
203 return strs.str();
204 }
205
206 protected:
207 std::shared_ptr<Channel> channel_;
208 std::unique_ptr<ServerBuilder> builder_;
209 std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
210 std::unique_ptr<ServerCompletionQueue> cq_;
211 std::unique_ptr<Server> server_;
212 std::thread* cq_thread_;
213 TestServiceImpl service_;
214 int port_;
215
216 private:
CheckPresent()217 TestServerBuilderPlugin* CheckPresent() {
218 auto it = builder_->plugins_.begin();
219 for (; it != builder_->plugins_.end(); it++) {
220 if ((*it)->name() == PLUGIN_NAME) break;
221 }
222 if (it != builder_->plugins_.end()) {
223 return static_cast<TestServerBuilderPlugin*>(it->get());
224 } else {
225 return nullptr;
226 }
227 }
228
RunCQ()229 void RunCQ() {
230 void* tag;
231 bool ok;
232 while (cq_->Next(&tag, &ok)) {
233 }
234 }
235 };
236
TEST_P(ServerBuilderPluginTest,PluginWithoutServiceTest)237 TEST_P(ServerBuilderPluginTest, PluginWithoutServiceTest) {
238 InsertPlugin();
239 StartServer();
240 }
241
TEST_P(ServerBuilderPluginTest,PluginWithServiceTest)242 TEST_P(ServerBuilderPluginTest, PluginWithServiceTest) {
243 InsertPluginWithTestService();
244 StartServer();
245 ResetStub();
246
247 EchoRequest request;
248 EchoResponse response;
249 request.set_message("Hello hello hello hello");
250 ClientContext context;
251 context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
252 Status s = stub_->Echo(&context, request, &response);
253 EXPECT_EQ(response.message(), request.message());
254 EXPECT_TRUE(s.ok());
255 }
256
257 INSTANTIATE_TEST_SUITE_P(ServerBuilderPluginTest, ServerBuilderPluginTest,
258 ::testing::Values(false, true));
259
260 } // namespace testing
261 } // namespace grpc
262
main(int argc,char ** argv)263 int main(int argc, char** argv) {
264 grpc::testing::TestEnvironment env(&argc, argv);
265 ::testing::InitGoogleTest(&argc, argv);
266 return RUN_ALL_TESTS();
267 }
268