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 <grpc/fork.h>
23 #include <grpc/grpc.h>
24 #include <grpc/support/time.h>
25 #include <grpcpp/channel.h>
26 #include <grpcpp/client_context.h>
27 #include <grpcpp/create_channel.h>
28 #include <grpcpp/server.h>
29 #include <grpcpp/server_builder.h>
30 #include <grpcpp/server_context.h>
31 #include <gtest/gtest.h>
32 #include <signal.h>
33
34 #include "absl/log/log.h"
35 #include "absl/strings/str_cat.h"
36 #include "src/core/util/fork.h"
37 #include "src/proto/grpc/testing/echo.grpc.pb.h"
38 #include "test/core/test_util/port.h"
39 #include "test/core/test_util/test_config.h"
40 #include "test/cpp/util/test_config.h"
41
42 namespace grpc {
43 namespace testing {
44 namespace {
45
46 class ServiceImpl final : public EchoTestService::Service {
BidiStream(ServerContext *,ServerReaderWriter<EchoResponse,EchoRequest> * stream)47 Status BidiStream(
48 ServerContext* /*context*/,
49 ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
50 EchoRequest request;
51 EchoResponse response;
52 while (stream->Read(&request)) {
53 LOG(INFO) << "recv msg " << request.message();
54 response.set_message(request.message());
55 stream->Write(response);
56 LOG(INFO) << "wrote msg " << response.message();
57 }
58 return Status::OK;
59 }
60 };
61
MakeStub(const std::string & addr)62 std::unique_ptr<EchoTestService::Stub> MakeStub(const std::string& addr) {
63 return EchoTestService::NewStub(
64 grpc::CreateChannel(addr, InsecureChannelCredentials()));
65 }
66
TEST(ClientForkTest,ClientCallsBeforeAndAfterForkSucceed)67 TEST(ClientForkTest, ClientCallsBeforeAndAfterForkSucceed) {
68 grpc_core::Fork::Enable(true);
69
70 int port = grpc_pick_unused_port_or_die();
71 std::string addr = absl::StrCat("localhost:", port);
72
73 pid_t server_pid = fork();
74 switch (server_pid) {
75 case -1: // fork failed
76 GTEST_FAIL() << "failure forking";
77 case 0: // post-fork child
78 {
79 ServiceImpl impl;
80 grpc::ServerBuilder builder;
81 builder.AddListeningPort(addr, grpc::InsecureServerCredentials());
82 builder.RegisterService(&impl);
83 std::unique_ptr<Server> server(builder.BuildAndStart());
84 server->Wait();
85 return;
86 }
87 default: // post-fork parent
88 break;
89 }
90
91 // Do a round trip before we fork.
92 // NOTE: without this scope, test running with the epoll1 poller will fail.
93 {
94 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
95 EchoRequest request;
96 EchoResponse response;
97 ClientContext context;
98 context.set_wait_for_ready(true);
99
100 auto stream = stub->BidiStream(&context);
101
102 request.set_message("Hello");
103 ASSERT_TRUE(stream->Write(request));
104 ASSERT_TRUE(stream->Read(&response));
105 ASSERT_EQ(response.message(), request.message());
106 }
107 // Fork and do round trips in the post-fork parent and child.
108 pid_t child_client_pid = fork();
109 switch (child_client_pid) {
110 case -1: // fork failed
111 GTEST_FAIL() << "fork failed";
112 case 0: // post-fork child
113 {
114 VLOG(2) << "In post-fork child";
115 EchoRequest request;
116 EchoResponse response;
117 ClientContext context;
118 context.set_wait_for_ready(true);
119
120 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
121 auto stream = stub->BidiStream(&context);
122
123 request.set_message("Hello again from child");
124 ASSERT_TRUE(stream->Write(request));
125 ASSERT_TRUE(stream->Read(&response));
126 ASSERT_EQ(response.message(), request.message());
127 exit(0);
128 }
129 default: // post-fork parent
130 {
131 VLOG(2) << "In post-fork parent";
132 EchoRequest request;
133 EchoResponse response;
134 ClientContext context;
135 context.set_wait_for_ready(true);
136
137 std::unique_ptr<EchoTestService::Stub> stub = MakeStub(addr);
138 auto stream = stub->BidiStream(&context);
139
140 request.set_message("Hello again from parent");
141 EXPECT_TRUE(stream->Write(request));
142 EXPECT_TRUE(stream->Read(&response));
143 EXPECT_EQ(response.message(), request.message());
144
145 // Wait for the post-fork child to exit; ensure it exited cleanly.
146 int child_status;
147 ASSERT_EQ(waitpid(child_client_pid, &child_status, 0), child_client_pid)
148 << "failed to get status of child client";
149 ASSERT_EQ(WEXITSTATUS(child_status), 0) << "child did not exit cleanly";
150 }
151 }
152
153 kill(server_pid, SIGINT);
154 }
155
156 } // namespace
157 } // namespace testing
158 } // namespace grpc
159
main(int argc,char ** argv)160 int main(int argc, char** argv) {
161 testing::InitGoogleTest(&argc, argv);
162 grpc::testing::InitTest(&argc, &argv, true);
163 grpc::testing::TestEnvironment env(&argc, argv);
164 grpc_init();
165 int res = RUN_ALL_TESTS();
166 grpc_shutdown();
167 return res;
168 }
169 #endif // GRPC_ENABLE_FORK_SUPPORT
170