• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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