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