• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2023 gRPC authors.
3 //
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
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 //
16 
17 #include "test/cpp/interop/pre_stop_hook_server.h"
18 
19 #include <gmock/gmock.h>
20 #include <grpc/grpc.h>
21 #include <grpcpp/grpcpp.h>
22 #include <grpcpp/support/status.h>
23 #include <gtest/gtest.h>
24 
25 #include <thread>
26 
27 #include "absl/strings/str_format.h"
28 #include "src/core/util/sync.h"
29 #include "src/proto/grpc/testing/empty.pb.h"
30 #include "src/proto/grpc/testing/messages.pb.h"
31 #include "src/proto/grpc/testing/test.grpc.pb.h"
32 #include "test/core/test_util/port.h"
33 #include "test/core/test_util/test_config.h"
34 
35 namespace grpc {
36 namespace testing {
37 namespace {
38 
39 struct CallInfo {
40  public:
41   ClientContext context;
42   Empty request;
43   Empty response;
44 
WaitForStatusgrpc::testing::__anonb09882d50111::CallInfo45   absl::optional<Status> WaitForStatus(
46       absl::Duration timeout = absl::Seconds(1)) {
47     grpc_core::MutexLock lock(&mu);
48     cv.WaitWithTimeout(&mu, timeout);
49     return status_;
50   }
51 
SetStatusgrpc::testing::__anonb09882d50111::CallInfo52   void SetStatus(const Status& status) {
53     grpc_core::MutexLock lock(&mu);
54     status_ = status;
55     cv.SignalAll();
56   }
57 
58  private:
59   grpc_core::Mutex mu;
60   grpc_core::CondVar cv;
61   absl::optional<Status> status_;
62 };
63 
ServerLoop(HookServiceImpl * service,int port,Server ** server,grpc_core::Mutex * mu,grpc_core::CondVar * condition)64 void ServerLoop(HookServiceImpl* service, int port, Server** server,
65                 grpc_core::Mutex* mu, grpc_core::CondVar* condition) {
66   ServerBuilder builder;
67   builder.AddListeningPort(absl::StrFormat("0.0.0.0:%d", port),
68                            grpc::InsecureServerCredentials());
69   builder.RegisterService(service);
70   auto s = builder.BuildAndStart();
71   {
72     grpc_core::MutexLock lock(mu);
73     *server = s.get();
74     condition->SignalAll();
75   }
76   s->Wait();
77 }
78 
TEST(StandalonePreStopHookServer,StartDoRequestStop)79 TEST(StandalonePreStopHookServer, StartDoRequestStop) {
80   int port = grpc_pick_unused_port_or_die();
81   PreStopHookServerManager server;
82   Status start_status = server.Start(port, 15);
83   ASSERT_TRUE(start_status.ok()) << start_status.error_message();
84   auto channel = CreateChannel(absl::StrFormat("127.0.0.1:%d", port),
85                                InsecureChannelCredentials());
86   ASSERT_TRUE(channel);
87   CallInfo info;
88   HookService::Stub stub(std::move(channel));
89   stub.async()->Hook(&info.context, &info.request, &info.response,
90                      [&info](const Status& status) { info.SetStatus(status); });
91   ASSERT_TRUE(server.TestOnlyExpectRequests(1));
92   server.Return(StatusCode::INTERNAL, "Just a test");
93   auto status = info.WaitForStatus();
94   ASSERT_TRUE(status.has_value());
95   EXPECT_EQ(status->error_code(), StatusCode::INTERNAL);
96   EXPECT_EQ(status->error_message(), "Just a test");
97 }
98 
TEST(StandalonePreStopHookServer,StartServerWhileAlreadyRunning)99 TEST(StandalonePreStopHookServer, StartServerWhileAlreadyRunning) {
100   int port = grpc_pick_unused_port_or_die();
101   PreStopHookServerManager server;
102   Status status = server.Start(port, 15);
103   ASSERT_TRUE(status.ok()) << status.error_message();
104   status = server.Start(port, 15);
105   ASSERT_EQ(status.error_code(), StatusCode::ALREADY_EXISTS)
106       << status.error_message();
107 }
108 
TEST(StandalonePreStopHookServer,StopServerWhileRequestPending)109 TEST(StandalonePreStopHookServer, StopServerWhileRequestPending) {
110   int port = grpc_pick_unused_port_or_die();
111   PreStopHookServerManager server;
112   Status start_status = server.Start(port, 15);
113   ASSERT_TRUE(start_status.ok()) << start_status.error_message();
114   auto channel = CreateChannel(absl::StrFormat("127.0.0.1:%d", port),
115                                InsecureChannelCredentials());
116   ASSERT_TRUE(channel);
117   CallInfo info;
118   HookService::Stub stub(std::move(channel));
119   stub.async()->Hook(&info.context, &info.request, &info.response,
120                      [&info](const Status& status) { info.SetStatus(status); });
121   ASSERT_TRUE(server.TestOnlyExpectRequests(1));
122   ASSERT_TRUE(server.Stop().ok());
123   auto status = info.WaitForStatus();
124   ASSERT_TRUE(status.has_value());
125   EXPECT_EQ(status->error_code(), StatusCode::ABORTED);
126 }
127 
TEST(StandalonePreStopHookServer,MultipleRequests)128 TEST(StandalonePreStopHookServer, MultipleRequests) {
129   int port = grpc_pick_unused_port_or_die();
130   PreStopHookServerManager server;
131   Status start_status = server.Start(port, 15);
132   ASSERT_TRUE(start_status.ok()) << start_status.error_message();
133   auto channel = CreateChannel(absl::StrFormat("127.0.0.1:%d", port),
134                                InsecureChannelCredentials());
135   ASSERT_TRUE(channel);
136   HookService::Stub stub(std::move(channel));
137   CallInfo info1, info2, info3;
138   server.Return(StatusCode::INTERNAL, "First");
139   stub.async()->Hook(&info1.context, &info1.request, &info1.response,
140                      [&](const Status& status) { info1.SetStatus(status); });
141   auto status = info1.WaitForStatus();
142   ASSERT_TRUE(status.has_value());
143   EXPECT_EQ(status->error_code(), StatusCode::INTERNAL);
144   EXPECT_EQ(status->error_message(), "First");
145   stub.async()->Hook(&info2.context, &info2.request, &info2.response,
146                      [&](const Status& status) { info2.SetStatus(status); });
147   ASSERT_TRUE(server.TestOnlyExpectRequests(1, absl::Milliseconds(500)));
148   stub.async()->Hook(&info3.context, &info3.request, &info3.response,
149                      [&](const Status& status) { info3.SetStatus(status); });
150   server.Return(StatusCode::RESOURCE_EXHAUSTED, "Second");
151   server.Return(StatusCode::DEADLINE_EXCEEDED, "Third");
152   status = info2.WaitForStatus();
153   ASSERT_TRUE(status.has_value());
154   EXPECT_EQ(status->error_code(), StatusCode::RESOURCE_EXHAUSTED);
155   EXPECT_EQ(status->error_message(), "Second");
156   status = info3.WaitForStatus();
157   ASSERT_TRUE(status.has_value());
158   EXPECT_EQ(status->error_code(), StatusCode::DEADLINE_EXCEEDED);
159   EXPECT_EQ(status->error_message(), "Third");
160 }
161 
TEST(StandalonePreStopHookServer,StopServerThatNotStarted)162 TEST(StandalonePreStopHookServer, StopServerThatNotStarted) {
163   PreStopHookServerManager server;
164   Status status = server.Stop();
165   EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE)
166       << status.error_message();
167 }
168 
TEST(StandalonePreStopHookServer,SetStatusBeforeRequestReceived)169 TEST(StandalonePreStopHookServer, SetStatusBeforeRequestReceived) {
170   int port = grpc_pick_unused_port_or_die();
171   PreStopHookServerManager server;
172   Status start_status = server.Start(port, 15);
173   server.Return(StatusCode::INTERNAL, "Just a test");
174   ASSERT_TRUE(start_status.ok()) << start_status.error_message();
175   auto channel = CreateChannel(absl::StrFormat("127.0.0.1:%d", port),
176                                InsecureChannelCredentials());
177   ASSERT_TRUE(channel);
178   HookService::Stub stub(std::move(channel));
179   CallInfo info;
180   auto status = stub.Hook(&info.context, info.request, &info.response);
181   EXPECT_EQ(status.error_code(), StatusCode::INTERNAL);
182   EXPECT_EQ(status.error_message(), "Just a test");
183 }
184 
TEST(PreStopHookService,StartDoRequestStop)185 TEST(PreStopHookService, StartDoRequestStop) {
186   int port = grpc_pick_unused_port_or_die();
187   grpc_core::Mutex mu;
188   grpc_core::CondVar condition;
189   Server* server = nullptr;
190   HookServiceImpl service;
191   std::thread server_thread(ServerLoop, &service, port, &server, &mu,
192                             &condition);
193   {
194     grpc_core::MutexLock lock(&mu);
195     while (server == nullptr) {
196       condition.Wait(&mu);
197     }
198   }
199   auto channel = CreateChannel(absl::StrFormat("127.0.0.1:%d", port),
200                                InsecureChannelCredentials());
201   ASSERT_TRUE(channel);
202   CallInfo infos[3];
203   HookService::Stub stub(std::move(channel));
204   stub.async()->Hook(
205       &infos[0].context, &infos[0].request, &infos[0].response,
206       [&infos](const Status& status) { infos[0].SetStatus(status); });
207   stub.async()->Hook(
208       &infos[1].context, &infos[1].request, &infos[1].response,
209       [&infos](const Status& status) { infos[1].SetStatus(status); });
210   ASSERT_TRUE(service.TestOnlyExpectRequests(
211       2, absl::Milliseconds(500) * grpc_test_slowdown_factor()));
212   ClientContext ctx;
213   SetReturnStatusRequest request;
214   request.set_grpc_code_to_return(StatusCode::INTERNAL);
215   request.set_grpc_status_description("Just a test");
216   Empty response;
217   ASSERT_EQ(stub.SetReturnStatus(&ctx, request, &response).error_code(),
218             StatusCode::OK);
219   auto status = infos[0].WaitForStatus();
220   ASSERT_TRUE(status.has_value());
221   EXPECT_EQ(status->error_code(), StatusCode::INTERNAL);
222   EXPECT_EQ(status->error_message(), "Just a test");
223   status = infos[1].WaitForStatus();
224   ASSERT_TRUE(status.has_value());
225   EXPECT_EQ(status->error_code(), StatusCode::INTERNAL);
226   EXPECT_EQ(status->error_message(), "Just a test");
227   status = stub.Hook(&infos[2].context, infos[2].request, &infos[2].response);
228   ASSERT_TRUE(status.has_value());
229   EXPECT_EQ(status->error_code(), StatusCode::INTERNAL);
230   EXPECT_EQ(status->error_message(), "Just a test");
231   CallInfo reset_call_info;
232   ASSERT_TRUE(stub.ClearReturnStatus(&reset_call_info.context,
233                                      reset_call_info.request,
234                                      &reset_call_info.response)
235                   .ok());
236   CallInfo call_hangs;
237   stub.async()->Hook(
238       &call_hangs.context, &call_hangs.request, &call_hangs.response,
239       [&](const Status& status) { call_hangs.SetStatus(status); });
240   ASSERT_TRUE(service.TestOnlyExpectRequests(
241       1, absl::Milliseconds(500) * grpc_test_slowdown_factor()));
242   status = call_hangs.WaitForStatus(absl::Milliseconds(100));
243   EXPECT_FALSE(status.has_value()) << status->error_message();
244   service.Stop();
245   EXPECT_EQ(call_hangs.WaitForStatus().value_or(Status::CANCELLED).error_code(),
246             StatusCode::ABORTED);
247   server->Shutdown();
248   server_thread.join();
249 }
250 
251 }  // namespace
252 }  // namespace testing
253 }  // namespace grpc
254 
main(int argc,char ** argv)255 int main(int argc, char** argv) {
256   ::testing::InitGoogleTest(&argc, argv);
257   grpc::testing::TestEnvironment env(&argc, argv);
258   auto result = RUN_ALL_TESTS();
259   return result;
260 }
261