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