1 // Copyright 2022 The gRPC Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #ifndef GRPC_ENABLE_FORK_SUPPORT
18 // No-op for builds without fork support.
main(int,char **)19 int main(int /* argc */, char** /* argv */) { return 0; }
20 #else // GRPC_ENABLE_FORK_SUPPORT
21
22 #include <signal.h>
23
24 #include <gtest/gtest.h>
25
26 #include "absl/strings/str_cat.h"
27
28 #include <grpc/fork.h>
29 #include <grpc/grpc.h>
30 #include <grpc/support/log.h>
31 #include <grpc/support/time.h>
32 #include <grpcpp/channel.h>
33 #include <grpcpp/client_context.h>
34 #include <grpcpp/create_channel.h>
35 #include <grpcpp/server.h>
36 #include <grpcpp/server_builder.h>
37 #include <grpcpp/server_context.h>
38
39 #include "src/core/lib/gprpp/fork.h"
40 #include "src/proto/grpc/testing/echo.grpc.pb.h"
41 #include "test/core/util/port.h"
42 #include "test/core/util/test_config.h"
43 #include "test/cpp/util/test_config.h"
44
45 namespace grpc {
46 namespace testing {
47 namespace {
48
49 class ServiceImpl final : public EchoTestService::Service {
BidiStream(ServerContext *,ServerReaderWriter<EchoResponse,EchoRequest> * stream)50 Status BidiStream(
51 ServerContext* /*context*/,
52 ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
53 EchoRequest request;
54 EchoResponse response;
55 while (stream->Read(&request)) {
56 gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
57 response.set_message(request.message());
58 stream->Write(response);
59 gpr_log(GPR_INFO, "wrote msg %s", response.message().c_str());
60 }
61 return Status::OK;
62 }
63 };
64
MakeStub(const std::string & addr)65 std::unique_ptr<EchoTestService::Stub> MakeStub(const std::string& addr) {
66 return EchoTestService::NewStub(
67 grpc::CreateChannel(addr, InsecureChannelCredentials()));
68 }
69
TEST(ClientForkTest,ClientCallsBeforeAndAfterForkSucceed)70 TEST(ClientForkTest, ClientCallsBeforeAndAfterForkSucceed) {
71 grpc_core::Fork::Enable(true);
72
73 int port = grpc_pick_unused_port_or_die();
74 std::string addr = absl::StrCat("localhost:", port);
75
76 pid_t server_pid = fork();
77 switch (server_pid) {
78 case -1: // fork failed
79 GTEST_FAIL() << "failure forking";
80 case 0: // post-fork child
81 {
82 ServiceImpl impl;
83 grpc::ServerBuilder builder;
84 builder.AddListeningPort(addr, grpc::InsecureServerCredentials());
85 builder.RegisterService(&impl);
86 std::unique_ptr<Server> server(builder.BuildAndStart());
87 server->Wait();
88 return;
89 }
90 default: // post-fork parent
91 break;
92 }
93
94 // Do a round trip before we fork.
95 // NOTE: without this scope, test running with the epoll1 poller will fail.
96 {
97 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
98 EchoRequest request;
99 EchoResponse response;
100 ClientContext context;
101 context.set_wait_for_ready(true);
102
103 auto stream = stub->BidiStream(&context);
104
105 request.set_message("Hello");
106 ASSERT_TRUE(stream->Write(request));
107 ASSERT_TRUE(stream->Read(&response));
108 ASSERT_EQ(response.message(), request.message());
109 }
110 // Fork and do round trips in the post-fork parent and child.
111 pid_t child_client_pid = fork();
112 switch (child_client_pid) {
113 case -1: // fork failed
114 GTEST_FAIL() << "fork failed";
115 case 0: // post-fork child
116 {
117 gpr_log(GPR_DEBUG, "In post-fork child");
118 EchoRequest request;
119 EchoResponse response;
120 ClientContext context;
121 context.set_wait_for_ready(true);
122
123 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
124 auto stream = stub->BidiStream(&context);
125
126 request.set_message("Hello again from child");
127 ASSERT_TRUE(stream->Write(request));
128 ASSERT_TRUE(stream->Read(&response));
129 ASSERT_EQ(response.message(), request.message());
130 exit(0);
131 }
132 default: // post-fork parent
133 {
134 gpr_log(GPR_DEBUG, "In post-fork parent");
135 EchoRequest request;
136 EchoResponse response;
137 ClientContext context;
138 context.set_wait_for_ready(true);
139
140 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
141 auto stream = stub->BidiStream(&context);
142
143 request.set_message("Hello again from parent");
144 EXPECT_TRUE(stream->Write(request));
145 EXPECT_TRUE(stream->Read(&response));
146 EXPECT_EQ(response.message(), request.message());
147
148 // Wait for the post-fork child to exit; ensure it exited cleanly.
149 int child_status;
150 ASSERT_EQ(waitpid(child_client_pid, &child_status, 0), child_client_pid)
151 << "failed to get status of child client";
152 ASSERT_EQ(WEXITSTATUS(child_status), 0) << "child did not exit cleanly";
153 }
154 }
155
156 kill(server_pid, SIGINT);
157 }
158
159 } // namespace
160 } // namespace testing
161 } // namespace grpc
162
main(int argc,char ** argv)163 int main(int argc, char** argv) {
164 testing::InitGoogleTest(&argc, argv);
165 grpc::testing::InitTest(&argc, &argv, true);
166 grpc::testing::TestEnvironment env(&argc, argv);
167 grpc_init();
168 int res = RUN_ALL_TESTS();
169 grpc_shutdown();
170 return res;
171 }
172 #endif // GRPC_ENABLE_FORK_SUPPORT
173