• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
20 #include <mutex>
21 #include <thread>
22 #include <vector>
23 
24 #include <grpc/grpc.h>
25 #include <grpc/support/log.h>
26 #include <grpcpp/channel.h>
27 #include <grpcpp/client_context.h>
28 #include <grpcpp/create_channel.h>
29 #include <grpcpp/ext/health_check_service_server_builder_option.h>
30 #include <grpcpp/health_check_service_interface.h>
31 #include <grpcpp/server.h>
32 #include <grpcpp/server_builder.h>
33 #include <grpcpp/server_context.h>
34 
35 #include "src/proto/grpc/health/v1/health.grpc.pb.h"
36 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
37 #include "src/proto/grpc/testing/echo.grpc.pb.h"
38 #include "test/core/util/port.h"
39 #include "test/core/util/test_config.h"
40 #include "test/cpp/end2end/test_service_impl.h"
41 
42 #include <gtest/gtest.h>
43 
44 using grpc::health::v1::Health;
45 using grpc::health::v1::HealthCheckRequest;
46 using grpc::health::v1::HealthCheckResponse;
47 
48 namespace grpc {
49 namespace testing {
50 namespace {
51 
52 // A sample sync implementation of the health checking service. This does the
53 // same thing as the default one.
54 class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service {
55  public:
Check(ServerContext * context,const HealthCheckRequest * request,HealthCheckResponse * response)56   Status Check(ServerContext* context, const HealthCheckRequest* request,
57                HealthCheckResponse* response) override {
58     std::lock_guard<std::mutex> lock(mu_);
59     auto iter = status_map_.find(request->service());
60     if (iter == status_map_.end()) {
61       return Status(StatusCode::NOT_FOUND, "");
62     }
63     response->set_status(iter->second);
64     return Status::OK;
65   }
66 
SetStatus(const grpc::string & service_name,HealthCheckResponse::ServingStatus status)67   void SetStatus(const grpc::string& service_name,
68                  HealthCheckResponse::ServingStatus status) {
69     std::lock_guard<std::mutex> lock(mu_);
70     status_map_[service_name] = status;
71   }
72 
SetAll(HealthCheckResponse::ServingStatus status)73   void SetAll(HealthCheckResponse::ServingStatus status) {
74     std::lock_guard<std::mutex> lock(mu_);
75     for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) {
76       iter->second = status;
77     }
78   }
79 
80  private:
81   std::mutex mu_;
82   std::map<const grpc::string, HealthCheckResponse::ServingStatus> status_map_;
83 };
84 
85 // A custom implementation of the health checking service interface. This is
86 // used to test that it prevents the server from creating a default service and
87 // also serves as an example of how to override the default service.
88 class CustomHealthCheckService : public HealthCheckServiceInterface {
89  public:
CustomHealthCheckService(HealthCheckServiceImpl * impl)90   explicit CustomHealthCheckService(HealthCheckServiceImpl* impl)
91       : impl_(impl) {
92     impl_->SetStatus("", HealthCheckResponse::SERVING);
93   }
SetServingStatus(const grpc::string & service_name,bool serving)94   void SetServingStatus(const grpc::string& service_name,
95                         bool serving) override {
96     impl_->SetStatus(service_name, serving ? HealthCheckResponse::SERVING
97                                            : HealthCheckResponse::NOT_SERVING);
98   }
99 
SetServingStatus(bool serving)100   void SetServingStatus(bool serving) override {
101     impl_->SetAll(serving ? HealthCheckResponse::SERVING
102                           : HealthCheckResponse::NOT_SERVING);
103   }
104 
105  private:
106   HealthCheckServiceImpl* impl_;  // not owned
107 };
108 
LoopCompletionQueue(ServerCompletionQueue * cq)109 void LoopCompletionQueue(ServerCompletionQueue* cq) {
110   void* tag;
111   bool ok;
112   while (cq->Next(&tag, &ok)) {
113     abort();  // Nothing should come out of the cq.
114   }
115 }
116 
117 class HealthServiceEnd2endTest : public ::testing::Test {
118  protected:
HealthServiceEnd2endTest()119   HealthServiceEnd2endTest() {}
120 
SetUpServer(bool register_sync_test_service,bool add_async_cq,bool explicit_health_service,std::unique_ptr<HealthCheckServiceInterface> service)121   void SetUpServer(bool register_sync_test_service, bool add_async_cq,
122                    bool explicit_health_service,
123                    std::unique_ptr<HealthCheckServiceInterface> service) {
124     int port = grpc_pick_unused_port_or_die();
125     server_address_ << "localhost:" << port;
126 
127     bool register_sync_health_service_impl =
128         explicit_health_service && service != nullptr;
129 
130     // Setup server
131     ServerBuilder builder;
132     if (explicit_health_service) {
133       std::unique_ptr<ServerBuilderOption> option(
134           new HealthCheckServiceServerBuilderOption(std::move(service)));
135       builder.SetOption(std::move(option));
136     }
137     builder.AddListeningPort(server_address_.str(),
138                              grpc::InsecureServerCredentials());
139     if (register_sync_test_service) {
140       // Register a sync service.
141       builder.RegisterService(&echo_test_service_);
142     }
143     if (register_sync_health_service_impl) {
144       builder.RegisterService(&health_check_service_impl_);
145     }
146     if (add_async_cq) {
147       cq_ = builder.AddCompletionQueue();
148     }
149     server_ = builder.BuildAndStart();
150   }
151 
TearDown()152   void TearDown() override {
153     if (server_) {
154       server_->Shutdown();
155       if (cq_ != nullptr) {
156         cq_->Shutdown();
157       }
158       if (cq_thread_.joinable()) {
159         cq_thread_.join();
160       }
161     }
162   }
163 
ResetStubs()164   void ResetStubs() {
165     std::shared_ptr<Channel> channel =
166         CreateChannel(server_address_.str(), InsecureChannelCredentials());
167     hc_stub_ = grpc::health::v1::Health::NewStub(channel);
168   }
169 
170   // When the expected_status is NOT OK, we do not care about the response.
SendHealthCheckRpc(const grpc::string & service_name,const Status & expected_status)171   void SendHealthCheckRpc(const grpc::string& service_name,
172                           const Status& expected_status) {
173     EXPECT_FALSE(expected_status.ok());
174     SendHealthCheckRpc(service_name, expected_status,
175                        HealthCheckResponse::UNKNOWN);
176   }
177 
SendHealthCheckRpc(const grpc::string & service_name,const Status & expected_status,HealthCheckResponse::ServingStatus expected_serving_status)178   void SendHealthCheckRpc(
179       const grpc::string& service_name, const Status& expected_status,
180       HealthCheckResponse::ServingStatus expected_serving_status) {
181     HealthCheckRequest request;
182     request.set_service(service_name);
183     HealthCheckResponse response;
184     ClientContext context;
185     Status s = hc_stub_->Check(&context, request, &response);
186     EXPECT_EQ(expected_status.error_code(), s.error_code());
187     if (s.ok()) {
188       EXPECT_EQ(expected_serving_status, response.status());
189     }
190   }
191 
VerifyHealthCheckService()192   void VerifyHealthCheckService() {
193     HealthCheckServiceInterface* service = server_->GetHealthCheckService();
194     EXPECT_TRUE(service != nullptr);
195     const grpc::string kHealthyService("healthy_service");
196     const grpc::string kUnhealthyService("unhealthy_service");
197     const grpc::string kNotRegisteredService("not_registered");
198     service->SetServingStatus(kHealthyService, true);
199     service->SetServingStatus(kUnhealthyService, false);
200 
201     ResetStubs();
202 
203     SendHealthCheckRpc("", Status::OK, HealthCheckResponse::SERVING);
204     SendHealthCheckRpc(kHealthyService, Status::OK,
205                        HealthCheckResponse::SERVING);
206     SendHealthCheckRpc(kUnhealthyService, Status::OK,
207                        HealthCheckResponse::NOT_SERVING);
208     SendHealthCheckRpc(kNotRegisteredService,
209                        Status(StatusCode::NOT_FOUND, ""));
210 
211     service->SetServingStatus(false);
212     SendHealthCheckRpc("", Status::OK, HealthCheckResponse::NOT_SERVING);
213     SendHealthCheckRpc(kHealthyService, Status::OK,
214                        HealthCheckResponse::NOT_SERVING);
215     SendHealthCheckRpc(kUnhealthyService, Status::OK,
216                        HealthCheckResponse::NOT_SERVING);
217     SendHealthCheckRpc(kNotRegisteredService,
218                        Status(StatusCode::NOT_FOUND, ""));
219   }
220 
221   TestServiceImpl echo_test_service_;
222   HealthCheckServiceImpl health_check_service_impl_;
223   std::unique_ptr<Health::Stub> hc_stub_;
224   std::unique_ptr<ServerCompletionQueue> cq_;
225   std::unique_ptr<Server> server_;
226   std::ostringstream server_address_;
227   std::thread cq_thread_;
228 };
229 
TEST_F(HealthServiceEnd2endTest,DefaultHealthServiceDisabled)230 TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceDisabled) {
231   EnableDefaultHealthCheckService(false);
232   EXPECT_FALSE(DefaultHealthCheckServiceEnabled());
233   SetUpServer(true, false, false, nullptr);
234   HealthCheckServiceInterface* default_service =
235       server_->GetHealthCheckService();
236   EXPECT_TRUE(default_service == nullptr);
237 
238   ResetStubs();
239 
240   SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
241 }
242 
TEST_F(HealthServiceEnd2endTest,DefaultHealthService)243 TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
244   EnableDefaultHealthCheckService(true);
245   EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
246   SetUpServer(true, false, false, nullptr);
247   VerifyHealthCheckService();
248 
249   // The default service has a size limit of the service name.
250   const grpc::string kTooLongServiceName(201, 'x');
251   SendHealthCheckRpc(kTooLongServiceName,
252                      Status(StatusCode::INVALID_ARGUMENT, ""));
253 }
254 
255 // The server has no sync service.
TEST_F(HealthServiceEnd2endTest,DefaultHealthServiceAsyncOnly)256 TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceAsyncOnly) {
257   EnableDefaultHealthCheckService(true);
258   EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
259   SetUpServer(false, true, false, nullptr);
260   cq_thread_ = std::thread(LoopCompletionQueue, cq_.get());
261 
262   HealthCheckServiceInterface* default_service =
263       server_->GetHealthCheckService();
264   EXPECT_TRUE(default_service == nullptr);
265 
266   ResetStubs();
267 
268   SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
269 }
270 
271 // Provide an empty service to disable the default service.
TEST_F(HealthServiceEnd2endTest,ExplicitlyDisableViaOverride)272 TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) {
273   EnableDefaultHealthCheckService(true);
274   EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
275   std::unique_ptr<HealthCheckServiceInterface> empty_service;
276   SetUpServer(true, false, true, std::move(empty_service));
277   HealthCheckServiceInterface* service = server_->GetHealthCheckService();
278   EXPECT_TRUE(service == nullptr);
279 
280   ResetStubs();
281 
282   SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
283 }
284 
285 // Provide an explicit override of health checking service interface.
TEST_F(HealthServiceEnd2endTest,ExplicitlyOverride)286 TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) {
287   EnableDefaultHealthCheckService(true);
288   EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
289   std::unique_ptr<HealthCheckServiceInterface> override_service(
290       new CustomHealthCheckService(&health_check_service_impl_));
291   HealthCheckServiceInterface* underlying_service = override_service.get();
292   SetUpServer(false, false, true, std::move(override_service));
293   HealthCheckServiceInterface* service = server_->GetHealthCheckService();
294   EXPECT_TRUE(service == underlying_service);
295 
296   ResetStubs();
297 
298   VerifyHealthCheckService();
299 }
300 
301 }  // namespace
302 }  // namespace testing
303 }  // namespace grpc
304 
main(int argc,char ** argv)305 int main(int argc, char** argv) {
306   grpc_test_init(argc, argv);
307   ::testing::InitGoogleTest(&argc, argv);
308   return RUN_ALL_TESTS();
309 }
310