| /* |
| * |
| * Copyright 2016 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| #include <thread> |
| |
| #include <grpc++/channel.h> |
| #include <grpc++/client_context.h> |
| #include <grpc++/create_channel.h> |
| #include <grpc++/impl/server_builder_option.h> |
| #include <grpc++/impl/server_builder_plugin.h> |
| #include <grpc++/impl/server_initializer.h> |
| #include <grpc++/security/credentials.h> |
| #include <grpc++/security/server_credentials.h> |
| #include <grpc++/server.h> |
| #include <grpc++/server_builder.h> |
| #include <grpc++/server_context.h> |
| #include <grpc/grpc.h> |
| |
| #include "src/proto/grpc/testing/echo.grpc.pb.h" |
| #include "test/core/util/port.h" |
| #include "test/core/util/test_config.h" |
| #include "test/cpp/end2end/test_service_impl.h" |
| |
| #include <gtest/gtest.h> |
| |
| #define PLUGIN_NAME "TestServerBuilderPlugin" |
| |
| namespace grpc { |
| namespace testing { |
| |
| class TestServerBuilderPlugin : public ServerBuilderPlugin { |
| public: |
| TestServerBuilderPlugin() : service_(new TestServiceImpl()) { |
| init_server_is_called_ = false; |
| finish_is_called_ = false; |
| change_arguments_is_called_ = false; |
| register_service_ = false; |
| } |
| |
| grpc::string name() override { return PLUGIN_NAME; } |
| |
| void InitServer(ServerInitializer* si) override { |
| init_server_is_called_ = true; |
| if (register_service_) { |
| si->RegisterService(service_); |
| } |
| } |
| |
| void Finish(ServerInitializer* si) override { finish_is_called_ = true; } |
| |
| void ChangeArguments(const grpc::string& name, void* value) override { |
| change_arguments_is_called_ = true; |
| } |
| |
| bool has_async_methods() const override { |
| if (register_service_) { |
| return service_->has_async_methods(); |
| } |
| return false; |
| } |
| |
| bool has_sync_methods() const override { |
| if (register_service_) { |
| return service_->has_synchronous_methods(); |
| } |
| return false; |
| } |
| |
| void SetRegisterService() { register_service_ = true; } |
| |
| bool init_server_is_called() { return init_server_is_called_; } |
| bool finish_is_called() { return finish_is_called_; } |
| bool change_arguments_is_called() { return change_arguments_is_called_; } |
| |
| private: |
| bool init_server_is_called_; |
| bool finish_is_called_; |
| bool change_arguments_is_called_; |
| bool register_service_; |
| std::shared_ptr<TestServiceImpl> service_; |
| }; |
| |
| class InsertPluginServerBuilderOption : public ServerBuilderOption { |
| public: |
| InsertPluginServerBuilderOption() { register_service_ = false; } |
| |
| void UpdateArguments(ChannelArguments* arg) override {} |
| |
| void UpdatePlugins( |
| std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) override { |
| plugins->clear(); |
| |
| std::unique_ptr<TestServerBuilderPlugin> plugin( |
| new TestServerBuilderPlugin()); |
| if (register_service_) plugin->SetRegisterService(); |
| plugins->emplace_back(std::move(plugin)); |
| } |
| |
| void SetRegisterService() { register_service_ = true; } |
| |
| private: |
| bool register_service_; |
| }; |
| |
| std::unique_ptr<ServerBuilderPlugin> CreateTestServerBuilderPlugin() { |
| return std::unique_ptr<ServerBuilderPlugin>(new TestServerBuilderPlugin()); |
| } |
| |
| void AddTestServerBuilderPlugin() { |
| static bool already_here = false; |
| if (already_here) return; |
| already_here = true; |
| ::grpc::ServerBuilder::InternalAddPluginFactory( |
| &CreateTestServerBuilderPlugin); |
| } |
| |
| // Force AddServerBuilderPlugin() to be called at static initialization time. |
| struct StaticTestPluginInitializer { |
| StaticTestPluginInitializer() { AddTestServerBuilderPlugin(); } |
| } static_plugin_initializer_test_; |
| |
| // When the param boolean is true, the ServerBuilder plugin will be added at the |
| // time of static initialization. When it's false, the ServerBuilder plugin will |
| // be added using ServerBuilder::SetOption(). |
| class ServerBuilderPluginTest : public ::testing::TestWithParam<bool> { |
| public: |
| ServerBuilderPluginTest() {} |
| |
| void SetUp() override { |
| port_ = grpc_pick_unused_port_or_die(); |
| builder_.reset(new ServerBuilder()); |
| } |
| |
| void InsertPlugin() { |
| if (GetParam()) { |
| // Add ServerBuilder plugin in static initialization |
| CheckPresent(); |
| } else { |
| // Add ServerBuilder plugin using ServerBuilder::SetOption() |
| builder_->SetOption(std::unique_ptr<ServerBuilderOption>( |
| new InsertPluginServerBuilderOption())); |
| } |
| } |
| |
| void InsertPluginWithTestService() { |
| if (GetParam()) { |
| // Add ServerBuilder plugin in static initialization |
| auto plugin = CheckPresent(); |
| EXPECT_TRUE(plugin); |
| plugin->SetRegisterService(); |
| } else { |
| // Add ServerBuilder plugin using ServerBuilder::SetOption() |
| std::unique_ptr<InsertPluginServerBuilderOption> option( |
| new InsertPluginServerBuilderOption()); |
| option->SetRegisterService(); |
| builder_->SetOption(std::move(option)); |
| } |
| } |
| |
| void StartServer() { |
| grpc::string server_address = "localhost:" + to_string(port_); |
| builder_->AddListeningPort(server_address, InsecureServerCredentials()); |
| // we run some tests without a service, and for those we need to supply a |
| // frequently polled completion queue |
| cq_ = builder_->AddCompletionQueue(); |
| cq_thread_ = new std::thread(&ServerBuilderPluginTest::RunCQ, this); |
| server_ = builder_->BuildAndStart(); |
| EXPECT_TRUE(CheckPresent()); |
| } |
| |
| void ResetStub() { |
| string target = "dns:localhost:" + to_string(port_); |
| channel_ = CreateChannel(target, InsecureChannelCredentials()); |
| stub_ = grpc::testing::EchoTestService::NewStub(channel_); |
| } |
| |
| void TearDown() override { |
| auto plugin = CheckPresent(); |
| EXPECT_TRUE(plugin); |
| EXPECT_TRUE(plugin->init_server_is_called()); |
| EXPECT_TRUE(plugin->finish_is_called()); |
| server_->Shutdown(); |
| cq_->Shutdown(); |
| cq_thread_->join(); |
| delete cq_thread_; |
| } |
| |
| string to_string(const int number) { |
| std::stringstream strs; |
| strs << number; |
| return strs.str(); |
| } |
| |
| protected: |
| std::shared_ptr<Channel> channel_; |
| std::unique_ptr<ServerBuilder> builder_; |
| std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; |
| std::unique_ptr<ServerCompletionQueue> cq_; |
| std::unique_ptr<Server> server_; |
| std::thread* cq_thread_; |
| TestServiceImpl service_; |
| int port_; |
| |
| private: |
| TestServerBuilderPlugin* CheckPresent() { |
| auto it = builder_->plugins_.begin(); |
| for (; it != builder_->plugins_.end(); it++) { |
| if ((*it)->name() == PLUGIN_NAME) break; |
| } |
| if (it != builder_->plugins_.end()) { |
| return static_cast<TestServerBuilderPlugin*>(it->get()); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| void RunCQ() { |
| void* tag; |
| bool ok; |
| while (cq_->Next(&tag, &ok)) |
| ; |
| } |
| }; |
| |
| TEST_P(ServerBuilderPluginTest, PluginWithoutServiceTest) { |
| InsertPlugin(); |
| StartServer(); |
| } |
| |
| TEST_P(ServerBuilderPluginTest, PluginWithServiceTest) { |
| InsertPluginWithTestService(); |
| StartServer(); |
| ResetStub(); |
| |
| EchoRequest request; |
| EchoResponse response; |
| request.set_message("Hello hello hello hello"); |
| ClientContext context; |
| context.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP); |
| Status s = stub_->Echo(&context, request, &response); |
| EXPECT_EQ(response.message(), request.message()); |
| EXPECT_TRUE(s.ok()); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(ServerBuilderPluginTest, ServerBuilderPluginTest, |
| ::testing::Values(false, true)); |
| |
| } // namespace testing |
| } // namespace grpc |
| |
| int main(int argc, char** argv) { |
| grpc_test_init(argc, argv); |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |