1 //
2 //
3 // Copyright 2019 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/grpc.h>
20 #include <grpc/support/time.h>
21 #include <grpcpp/channel.h>
22 #include <grpcpp/client_context.h>
23 #include <grpcpp/create_channel.h>
24 #include <grpcpp/server.h>
25 #include <grpcpp/server_builder.h>
26 #include <grpcpp/server_context.h>
27 #include <gtest/gtest.h>
28 #include <sys/time.h>
29
30 #include <thread>
31
32 #include "absl/log/check.h"
33 #include "absl/memory/memory.h"
34 #include "src/core/lib/iomgr/timer.h"
35 #include "src/core/util/crash.h"
36 #include "src/proto/grpc/testing/echo.grpc.pb.h"
37 #include "test/core/test_util/port.h"
38 #include "test/core/test_util/test_config.h"
39 #include "test/cpp/end2end/test_service_impl.h"
40 #include "test/cpp/util/subprocess.h"
41
42 static std::string g_root;
43
44 static gpr_mu g_mu;
45 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
46 gpr_timespec (*gpr_now_impl_orig)(gpr_clock_type clock_type) = gpr_now_impl;
47 static int g_time_shift_sec = 0;
48 static int g_time_shift_nsec = 0;
now_impl(gpr_clock_type clock)49 static gpr_timespec now_impl(gpr_clock_type clock) {
50 auto ts = gpr_now_impl_orig(clock);
51 // We only manipulate the realtime clock to simulate changes in wall-clock
52 // time
53 if (clock != GPR_CLOCK_REALTIME) {
54 return ts;
55 }
56 CHECK_GE(ts.tv_nsec, 0);
57 CHECK_LT(ts.tv_nsec, GPR_NS_PER_SEC);
58 gpr_mu_lock(&g_mu);
59 ts.tv_sec += g_time_shift_sec;
60 ts.tv_nsec += g_time_shift_nsec;
61 gpr_mu_unlock(&g_mu);
62 if (ts.tv_nsec >= GPR_NS_PER_SEC) {
63 ts.tv_nsec -= GPR_NS_PER_SEC;
64 ++ts.tv_sec;
65 } else if (ts.tv_nsec < 0) {
66 --ts.tv_sec;
67 ts.tv_nsec = GPR_NS_PER_SEC + ts.tv_nsec;
68 }
69 return ts;
70 }
71
72 // offset the value returned by gpr_now(GPR_CLOCK_REALTIME) by msecs
73 // milliseconds
set_now_offset(int msecs)74 static void set_now_offset(int msecs) {
75 gpr_mu_lock(&g_mu);
76 g_time_shift_sec = msecs / 1000;
77 g_time_shift_nsec = (msecs % 1000) * 1e6;
78 gpr_mu_unlock(&g_mu);
79 }
80
81 // restore the original implementation of gpr_now()
reset_now_offset()82 static void reset_now_offset() {
83 gpr_mu_lock(&g_mu);
84 g_time_shift_sec = 0;
85 g_time_shift_nsec = 0;
86 gpr_mu_unlock(&g_mu);
87 }
88
89 namespace grpc {
90 namespace testing {
91
92 namespace {
93
94 // gpr_now() is called with invalid clock_type
TEST(TimespecTest,GprNowInvalidClockType)95 TEST(TimespecTest, GprNowInvalidClockType) {
96 // initialize to some junk value
97 gpr_clock_type invalid_clock_type = static_cast<gpr_clock_type>(32641);
98 EXPECT_DEATH(gpr_now(invalid_clock_type), ".*");
99 }
100
101 // Add timespan with negative nanoseconds
TEST(TimespecTest,GprTimeAddNegativeNs)102 TEST(TimespecTest, GprTimeAddNegativeNs) {
103 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
104 gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
105 EXPECT_DEATH(gpr_time_add(now, bad_ts), ".*");
106 }
107
108 // Subtract timespan with negative nanoseconds
TEST(TimespecTest,GprTimeSubNegativeNs)109 TEST(TimespecTest, GprTimeSubNegativeNs) {
110 // Nanoseconds must always be positive. Negative timestamps are represented by
111 // (negative seconds, positive nanoseconds)
112 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
113 gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
114 EXPECT_DEATH(gpr_time_sub(now, bad_ts), ".*");
115 }
116
117 // Add negative milliseconds to gpr_timespec
TEST(TimespecTest,GrpcNegativeMillisToTimespec)118 TEST(TimespecTest, GrpcNegativeMillisToTimespec) {
119 // -1500 milliseconds converts to timespec (-2 secs, 5 * 10^8 nsec)
120 gpr_timespec ts =
121 grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(-1500)
122 .as_timespec(GPR_CLOCK_MONOTONIC);
123 CHECK(ts.tv_sec = -2);
124 CHECK(ts.tv_nsec = 5e8);
125 CHECK_EQ(ts.clock_type, GPR_CLOCK_MONOTONIC);
126 }
127
128 class TimeChangeTest : public ::testing::Test {
129 protected:
TimeChangeTest()130 TimeChangeTest() {}
131
SetUpTestSuite()132 static void SetUpTestSuite() {
133 auto port = grpc_pick_unused_port_or_die();
134 std::ostringstream addr_stream;
135 addr_stream << "localhost:" << port;
136 server_address_ = addr_stream.str();
137 server_ = std::make_unique<SubProcess>(std::vector<std::string>({
138 g_root + "/client_crash_test_server",
139 "--address=" + server_address_,
140 }));
141 CHECK(server_);
142 // connect to server and make sure it's reachable.
143 auto channel =
144 grpc::CreateChannel(server_address_, InsecureChannelCredentials());
145 CHECK(channel);
146 EXPECT_TRUE(channel->WaitForConnected(
147 grpc_timeout_milliseconds_to_deadline(30000)));
148 }
149
TearDownTestSuite()150 static void TearDownTestSuite() { server_.reset(); }
151
SetUp()152 void SetUp() override {
153 channel_ =
154 grpc::CreateChannel(server_address_, InsecureChannelCredentials());
155 CHECK(channel_);
156 stub_ = grpc::testing::EchoTestService::NewStub(channel_);
157 }
158
TearDown()159 void TearDown() override { reset_now_offset(); }
160
CreateStub()161 std::unique_ptr<grpc::testing::EchoTestService::Stub> CreateStub() {
162 return grpc::testing::EchoTestService::NewStub(channel_);
163 }
164
GetChannel()165 std::shared_ptr<Channel> GetChannel() { return channel_; }
166 // time jump offsets in milliseconds
167 const int TIME_OFFSET1 = 20123;
168 const int TIME_OFFSET2 = 5678;
169
170 private:
171 static std::string server_address_;
172 static std::unique_ptr<SubProcess> server_;
173 std::shared_ptr<Channel> channel_;
174 std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
175 };
176 std::string TimeChangeTest::server_address_;
177 std::unique_ptr<SubProcess> TimeChangeTest::server_;
178
179 // Wall-clock time jumps forward on client before bidi stream is created
TEST_F(TimeChangeTest,TimeJumpForwardBeforeStreamCreated)180 TEST_F(TimeChangeTest, TimeJumpForwardBeforeStreamCreated) {
181 EchoRequest request;
182 EchoResponse response;
183 ClientContext context;
184 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
185 context.AddMetadata(kServerResponseStreamsToSend, "1");
186
187 auto channel = GetChannel();
188 CHECK(channel);
189 EXPECT_TRUE(
190 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
191 auto stub = CreateStub();
192
193 // time jumps forward by TIME_OFFSET1 milliseconds
194 set_now_offset(TIME_OFFSET1);
195 auto stream = stub->BidiStream(&context);
196 request.set_message("Hello");
197 EXPECT_TRUE(stream->Write(request));
198
199 EXPECT_TRUE(stream->WritesDone());
200 EXPECT_TRUE(stream->Read(&response));
201
202 auto status = stream->Finish();
203 EXPECT_TRUE(status.ok());
204 }
205
206 // Wall-clock time jumps back on client before bidi stream is created
TEST_F(TimeChangeTest,TimeJumpBackBeforeStreamCreated)207 TEST_F(TimeChangeTest, TimeJumpBackBeforeStreamCreated) {
208 EchoRequest request;
209 EchoResponse response;
210 ClientContext context;
211 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
212 context.AddMetadata(kServerResponseStreamsToSend, "1");
213
214 auto channel = GetChannel();
215 CHECK(channel);
216 EXPECT_TRUE(
217 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
218 auto stub = CreateStub();
219
220 // time jumps back by TIME_OFFSET1 milliseconds
221 set_now_offset(-TIME_OFFSET1);
222 auto stream = stub->BidiStream(&context);
223 request.set_message("Hello");
224 EXPECT_TRUE(stream->Write(request));
225
226 EXPECT_TRUE(stream->WritesDone());
227 EXPECT_TRUE(stream->Read(&response));
228 EXPECT_EQ(request.message(), response.message());
229
230 auto status = stream->Finish();
231 EXPECT_TRUE(status.ok());
232 }
233
234 // Wall-clock time jumps forward on client while call is in progress
TEST_F(TimeChangeTest,TimeJumpForwardAfterStreamCreated)235 TEST_F(TimeChangeTest, TimeJumpForwardAfterStreamCreated) {
236 EchoRequest request;
237 EchoResponse response;
238 ClientContext context;
239 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
240 context.AddMetadata(kServerResponseStreamsToSend, "2");
241
242 auto channel = GetChannel();
243 CHECK(channel);
244 EXPECT_TRUE(
245 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
246 auto stub = CreateStub();
247
248 auto stream = stub->BidiStream(&context);
249
250 request.set_message("Hello");
251 EXPECT_TRUE(stream->Write(request));
252 EXPECT_TRUE(stream->Read(&response));
253
254 // time jumps forward by TIME_OFFSET1 milliseconds.
255 set_now_offset(TIME_OFFSET1);
256
257 request.set_message("World");
258 EXPECT_TRUE(stream->Write(request));
259 EXPECT_TRUE(stream->WritesDone());
260 EXPECT_TRUE(stream->Read(&response));
261
262 auto status = stream->Finish();
263 EXPECT_TRUE(status.ok());
264 }
265
266 // Wall-clock time jumps back on client while call is in progress
TEST_F(TimeChangeTest,TimeJumpBackAfterStreamCreated)267 TEST_F(TimeChangeTest, TimeJumpBackAfterStreamCreated) {
268 EchoRequest request;
269 EchoResponse response;
270 ClientContext context;
271 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
272 context.AddMetadata(kServerResponseStreamsToSend, "2");
273
274 auto channel = GetChannel();
275 CHECK(channel);
276 EXPECT_TRUE(
277 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
278 auto stub = CreateStub();
279
280 auto stream = stub->BidiStream(&context);
281
282 request.set_message("Hello");
283 EXPECT_TRUE(stream->Write(request));
284 EXPECT_TRUE(stream->Read(&response));
285
286 // time jumps back TIME_OFFSET1 milliseconds.
287 set_now_offset(-TIME_OFFSET1);
288
289 request.set_message("World");
290 EXPECT_TRUE(stream->Write(request));
291 EXPECT_TRUE(stream->WritesDone());
292 EXPECT_TRUE(stream->Read(&response));
293
294 auto status = stream->Finish();
295 EXPECT_TRUE(status.ok());
296 }
297
298 // Wall-clock time jumps forward and backwards during call
TEST_F(TimeChangeTest,TimeJumpForwardAndBackDuringCall)299 TEST_F(TimeChangeTest, TimeJumpForwardAndBackDuringCall) {
300 EchoRequest request;
301 EchoResponse response;
302 ClientContext context;
303 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
304 context.AddMetadata(kServerResponseStreamsToSend, "2");
305
306 auto channel = GetChannel();
307 CHECK(channel);
308
309 EXPECT_TRUE(
310 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
311 auto stub = CreateStub();
312 auto stream = stub->BidiStream(&context);
313
314 request.set_message("Hello");
315 EXPECT_TRUE(stream->Write(request));
316
317 // time jumps back by TIME_OFFSET2 milliseconds
318 set_now_offset(-TIME_OFFSET2);
319
320 EXPECT_TRUE(stream->Read(&response));
321 request.set_message("World");
322
323 // time jumps forward by TIME_OFFSET milliseconds
324 set_now_offset(TIME_OFFSET1);
325
326 EXPECT_TRUE(stream->Write(request));
327
328 // time jumps back by TIME_OFFSET2 milliseconds
329 set_now_offset(-TIME_OFFSET2);
330
331 EXPECT_TRUE(stream->WritesDone());
332
333 // time jumps back by TIME_OFFSET2 milliseconds
334 set_now_offset(-TIME_OFFSET2);
335
336 EXPECT_TRUE(stream->Read(&response));
337
338 // time jumps back by TIME_OFFSET2 milliseconds
339 set_now_offset(-TIME_OFFSET2);
340
341 auto status = stream->Finish();
342 EXPECT_TRUE(status.ok());
343 }
344
345 } // namespace
346
347 } // namespace testing
348 } // namespace grpc
349
main(int argc,char ** argv)350 int main(int argc, char** argv) {
351 std::string me = argv[0];
352 // get index of last slash in path to test binary
353 auto lslash = me.rfind('/');
354 // set g_root = path to directory containing test binary
355 if (lslash != std::string::npos) {
356 g_root = me.substr(0, lslash);
357 } else {
358 g_root = ".";
359 }
360
361 gpr_mu_init(&g_mu);
362 gpr_now_impl = now_impl;
363
364 grpc::testing::TestEnvironment env(&argc, argv);
365 ::testing::InitGoogleTest(&argc, argv);
366 auto ret = RUN_ALL_TESTS();
367 return ret;
368 }
369