3 * Copyright 2019 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
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"
36 #include <gtest/gtest.h>
41 using grpc::testing::EchoRequest;
42 using grpc::testing::EchoResponse;
44 static std::string g_root;
47 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
48 gpr_timespec (*gpr_now_impl_orig)(gpr_clock_type clock_type) = gpr_now_impl;
49 static int g_time_shift_sec = 0;
50 static int g_time_shift_nsec = 0;
51 static gpr_timespec now_impl(gpr_clock_type clock) {
52 auto ts = gpr_now_impl_orig(clock);
53 // We only manipulate the realtime clock to simulate changes in wall-clock
55 if (clock != GPR_CLOCK_REALTIME) {
58 GPR_ASSERT(ts.tv_nsec >= 0);
59 GPR_ASSERT(ts.tv_nsec < GPR_NS_PER_SEC);
61 ts.tv_sec += g_time_shift_sec;
62 ts.tv_nsec += g_time_shift_nsec;
64 if (ts.tv_nsec >= GPR_NS_PER_SEC) {
65 ts.tv_nsec -= GPR_NS_PER_SEC;
67 } else if (ts.tv_nsec < 0) {
69 ts.tv_nsec = GPR_NS_PER_SEC + ts.tv_nsec;
74 // offset the value returned by gpr_now(GPR_CLOCK_REALTIME) by msecs
76 static void set_now_offset(int msecs) {
78 g_time_shift_sec = msecs / 1000;
79 g_time_shift_nsec = (msecs % 1000) * 1e6;
83 // restore the original implementation of gpr_now()
84 static void reset_now_offset() {
87 g_time_shift_nsec = 0;
96 // gpr_now() is called with invalid clock_type
97 TEST(TimespecTest, GprNowInvalidClockType) {
98 // initialize to some junk value
99 gpr_clock_type invalid_clock_type = (gpr_clock_type)32641;
100 EXPECT_DEATH(gpr_now(invalid_clock_type), ".*");
103 // Add timespan with negative nanoseconds
104 TEST(TimespecTest, GprTimeAddNegativeNs) {
105 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
106 gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
107 EXPECT_DEATH(gpr_time_add(now, bad_ts), ".*");
110 // Subtract timespan with negative nanoseconds
111 TEST(TimespecTest, GprTimeSubNegativeNs) {
112 // Nanoseconds must always be positive. Negative timestamps are represented by
113 // (negative seconds, positive nanoseconds)
114 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
115 gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
116 EXPECT_DEATH(gpr_time_sub(now, bad_ts), ".*");
119 // Add negative milliseconds to gpr_timespec
120 TEST(TimespecTest, GrpcNegativeMillisToTimespec) {
121 // -1500 milliseconds converts to timespec (-2 secs, 5 * 10^8 nsec)
122 gpr_timespec ts = grpc_millis_to_timespec(-1500, GPR_CLOCK_MONOTONIC);
123 GPR_ASSERT(ts.tv_sec = -2);
124 GPR_ASSERT(ts.tv_nsec = 5e8);
125 GPR_ASSERT(ts.clock_type == GPR_CLOCK_MONOTONIC);
128 class TimeChangeTest : public ::testing::Test {
133 auto port = grpc_pick_unused_port_or_die();
134 std::ostringstream addr_stream;
135 addr_stream << "localhost:" << port;
136 auto addr = addr_stream.str();
137 server_.reset(new SubProcess({
138 g_root + "/client_crash_test_server",
142 channel_ = grpc::CreateChannel(addr, InsecureChannelCredentials());
143 GPR_ASSERT(channel_);
144 stub_ = grpc::testing::EchoTestService::NewStub(channel_);
152 std::unique_ptr<grpc::testing::EchoTestService::Stub> CreateStub() {
153 return grpc::testing::EchoTestService::NewStub(channel_);
156 std::shared_ptr<Channel> GetChannel() { return channel_; }
157 // time jump offsets in milliseconds
158 const int TIME_OFFSET1 = 20123;
159 const int TIME_OFFSET2 = 5678;
162 std::unique_ptr<SubProcess> server_;
163 std::shared_ptr<Channel> channel_;
164 std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
167 // Wall-clock time jumps forward on client before bidi stream is created
168 TEST_F(TimeChangeTest, TimeJumpForwardBeforeStreamCreated) {
170 EchoResponse response;
171 ClientContext context;
172 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
173 context.AddMetadata(kServerResponseStreamsToSend, "1");
175 auto channel = GetChannel();
178 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
179 auto stub = CreateStub();
181 // time jumps forward by TIME_OFFSET1 milliseconds
182 set_now_offset(TIME_OFFSET1);
183 auto stream = stub->BidiStream(&context);
184 request.set_message("Hello");
185 EXPECT_TRUE(stream->Write(request));
187 EXPECT_TRUE(stream->WritesDone());
188 EXPECT_TRUE(stream->Read(&response));
190 auto status = stream->Finish();
191 EXPECT_TRUE(status.ok());
194 // Wall-clock time jumps back on client before bidi stream is created
195 TEST_F(TimeChangeTest, TimeJumpBackBeforeStreamCreated) {
197 EchoResponse response;
198 ClientContext context;
199 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
200 context.AddMetadata(kServerResponseStreamsToSend, "1");
202 auto channel = GetChannel();
205 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
206 auto stub = CreateStub();
208 // time jumps back by TIME_OFFSET1 milliseconds
209 set_now_offset(-TIME_OFFSET1);
210 auto stream = stub->BidiStream(&context);
211 request.set_message("Hello");
212 EXPECT_TRUE(stream->Write(request));
214 EXPECT_TRUE(stream->WritesDone());
215 EXPECT_TRUE(stream->Read(&response));
216 EXPECT_EQ(request.message(), response.message());
218 auto status = stream->Finish();
219 EXPECT_TRUE(status.ok());
222 // Wall-clock time jumps forward on client while call is in progress
223 TEST_F(TimeChangeTest, TimeJumpForwardAfterStreamCreated) {
225 EchoResponse response;
226 ClientContext context;
227 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
228 context.AddMetadata(kServerResponseStreamsToSend, "2");
230 auto channel = GetChannel();
233 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
234 auto stub = CreateStub();
236 auto stream = stub->BidiStream(&context);
238 request.set_message("Hello");
239 EXPECT_TRUE(stream->Write(request));
240 EXPECT_TRUE(stream->Read(&response));
242 // time jumps forward by TIME_OFFSET1 milliseconds.
243 set_now_offset(TIME_OFFSET1);
245 request.set_message("World");
246 EXPECT_TRUE(stream->Write(request));
247 EXPECT_TRUE(stream->WritesDone());
248 EXPECT_TRUE(stream->Read(&response));
250 auto status = stream->Finish();
251 EXPECT_TRUE(status.ok());
254 // Wall-clock time jumps back on client while call is in progress
255 TEST_F(TimeChangeTest, TimeJumpBackAfterStreamCreated) {
257 EchoResponse response;
258 ClientContext context;
259 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
260 context.AddMetadata(kServerResponseStreamsToSend, "2");
262 auto channel = GetChannel();
265 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
266 auto stub = CreateStub();
268 auto stream = stub->BidiStream(&context);
270 request.set_message("Hello");
271 EXPECT_TRUE(stream->Write(request));
272 EXPECT_TRUE(stream->Read(&response));
274 // time jumps back TIME_OFFSET1 milliseconds.
275 set_now_offset(-TIME_OFFSET1);
277 request.set_message("World");
278 EXPECT_TRUE(stream->Write(request));
279 EXPECT_TRUE(stream->WritesDone());
280 EXPECT_TRUE(stream->Read(&response));
282 auto status = stream->Finish();
283 EXPECT_TRUE(status.ok());
286 // Wall-clock time jumps forward on client before connection to server is up
287 TEST_F(TimeChangeTest, TimeJumpForwardBeforeServerConnect) {
289 EchoResponse response;
290 ClientContext context;
291 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
292 context.AddMetadata(kServerResponseStreamsToSend, "2");
294 auto channel = GetChannel();
297 // time jumps forward by TIME_OFFSET2 milliseconds
298 set_now_offset(TIME_OFFSET2);
301 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000));
302 // We use monotonic clock for pthread_cond_timedwait() deadline on linux, and
303 // realtime clock on other platforms - see gpr_cv_wait() in sync_posix.cc.
304 // So changes in system clock affect deadlines on non-linux platforms
307 auto stub = CreateStub();
308 auto stream = stub->BidiStream(&context);
310 request.set_message("Hello");
311 EXPECT_TRUE(stream->Write(request));
312 EXPECT_TRUE(stream->Read(&response));
313 request.set_message("World");
314 EXPECT_TRUE(stream->Write(request));
315 EXPECT_TRUE(stream->WritesDone());
316 EXPECT_TRUE(stream->Read(&response));
318 auto status = stream->Finish();
319 EXPECT_TRUE(status.ok());
325 // Wall-clock time jumps back on client before connection to server is up
326 TEST_F(TimeChangeTest, TimeJumpBackBeforeServerConnect) {
328 EchoResponse response;
329 ClientContext context;
330 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
331 context.AddMetadata(kServerResponseStreamsToSend, "2");
333 auto channel = GetChannel();
336 // time jumps back by TIME_OFFSET2 milliseconds
337 set_now_offset(-TIME_OFFSET2);
340 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
341 auto stub = CreateStub();
342 auto stream = stub->BidiStream(&context);
344 request.set_message("Hello");
345 EXPECT_TRUE(stream->Write(request));
346 EXPECT_TRUE(stream->Read(&response));
347 request.set_message("World");
348 EXPECT_TRUE(stream->Write(request));
349 EXPECT_TRUE(stream->WritesDone());
350 EXPECT_TRUE(stream->Read(&response));
352 auto status = stream->Finish();
353 EXPECT_TRUE(status.ok());
356 // Wall-clock time jumps forward and backwards during call
357 TEST_F(TimeChangeTest, TimeJumpForwardAndBackDuringCall) {
359 EchoResponse response;
360 ClientContext context;
361 context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
362 context.AddMetadata(kServerResponseStreamsToSend, "2");
364 auto channel = GetChannel();
368 channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
369 auto stub = CreateStub();
370 auto stream = stub->BidiStream(&context);
372 request.set_message("Hello");
373 EXPECT_TRUE(stream->Write(request));
375 // time jumps back by TIME_OFFSET2 milliseconds
376 set_now_offset(-TIME_OFFSET2);
378 EXPECT_TRUE(stream->Read(&response));
379 request.set_message("World");
381 // time jumps forward by TIME_OFFSET milliseconds
382 set_now_offset(TIME_OFFSET1);
384 EXPECT_TRUE(stream->Write(request));
386 // time jumps back by TIME_OFFSET2 milliseconds
387 set_now_offset(-TIME_OFFSET2);
389 EXPECT_TRUE(stream->WritesDone());
391 // time jumps back by TIME_OFFSET2 milliseconds
392 set_now_offset(-TIME_OFFSET2);
394 EXPECT_TRUE(stream->Read(&response));
396 // time jumps back by TIME_OFFSET2 milliseconds
397 set_now_offset(-TIME_OFFSET2);
399 auto status = stream->Finish();
400 EXPECT_TRUE(status.ok());
405 } // namespace testing
408 int main(int argc, char** argv) {
409 std::string me = argv[0];
410 // get index of last slash in path to test binary
411 auto lslash = me.rfind('/');
412 // set g_root = path to directory containing test binary
413 if (lslash != std::string::npos) {
414 g_root = me.substr(0, lslash);
420 gpr_now_impl = now_impl;
422 grpc::testing::TestEnvironment env(argc, argv);
423 ::testing::InitGoogleTest(&argc, argv);
424 auto ret = RUN_ALL_TESTS();