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