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