Imported Upstream version 1.21.0
[platform/upstream/grpc.git] / test / cpp / end2end / time_change_test.cc
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 <pthread.h>
38 #include <sys/time.h>
39 #include <thread>
40
41 using grpc::testing::EchoRequest;
42 using grpc::testing::EchoResponse;
43
44 static std::string g_root;
45
46 static gpr_mu g_mu;
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
54   // time
55   if (clock != GPR_CLOCK_REALTIME) {
56     return ts;
57   }
58   GPR_ASSERT(ts.tv_nsec >= 0);
59   GPR_ASSERT(ts.tv_nsec < GPR_NS_PER_SEC);
60   gpr_mu_lock(&g_mu);
61   ts.tv_sec += g_time_shift_sec;
62   ts.tv_nsec += g_time_shift_nsec;
63   gpr_mu_unlock(&g_mu);
64   if (ts.tv_nsec >= GPR_NS_PER_SEC) {
65     ts.tv_nsec -= GPR_NS_PER_SEC;
66     ++ts.tv_sec;
67   } else if (ts.tv_nsec < 0) {
68     --ts.tv_sec;
69     ts.tv_nsec = GPR_NS_PER_SEC + ts.tv_nsec;
70   }
71   return ts;
72 }
73
74 // offset the value returned by gpr_now(GPR_CLOCK_REALTIME) by msecs
75 // milliseconds
76 static void set_now_offset(int msecs) {
77   gpr_mu_lock(&g_mu);
78   g_time_shift_sec = msecs / 1000;
79   g_time_shift_nsec = (msecs % 1000) * 1e6;
80   gpr_mu_unlock(&g_mu);
81 }
82
83 // restore the original implementation of gpr_now()
84 static void reset_now_offset() {
85   gpr_mu_lock(&g_mu);
86   g_time_shift_sec = 0;
87   g_time_shift_nsec = 0;
88   gpr_mu_unlock(&g_mu);
89 }
90
91 namespace grpc {
92 namespace testing {
93
94 namespace {
95
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), ".*");
101 }
102
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), ".*");
108 }
109
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), ".*");
117 }
118
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);
126 }
127
128 class TimeChangeTest : public ::testing::Test {
129  protected:
130   TimeChangeTest() {}
131
132   void SetUp() {
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",
139         "--address=" + addr,
140     }));
141     GPR_ASSERT(server_);
142     channel_ = grpc::CreateChannel(addr, InsecureChannelCredentials());
143     GPR_ASSERT(channel_);
144     stub_ = grpc::testing::EchoTestService::NewStub(channel_);
145   }
146
147   void TearDown() {
148     server_.reset();
149     reset_now_offset();
150   }
151
152   std::unique_ptr<grpc::testing::EchoTestService::Stub> CreateStub() {
153     return grpc::testing::EchoTestService::NewStub(channel_);
154   }
155
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;
160
161  private:
162   std::unique_ptr<SubProcess> server_;
163   std::shared_ptr<Channel> channel_;
164   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
165 };
166
167 // Wall-clock time jumps forward on client before bidi stream is created
168 TEST_F(TimeChangeTest, TimeJumpForwardBeforeStreamCreated) {
169   EchoRequest request;
170   EchoResponse response;
171   ClientContext context;
172   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
173   context.AddMetadata(kServerResponseStreamsToSend, "1");
174
175   auto channel = GetChannel();
176   GPR_ASSERT(channel);
177   EXPECT_TRUE(
178       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
179   auto stub = CreateStub();
180
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));
186
187   EXPECT_TRUE(stream->WritesDone());
188   EXPECT_TRUE(stream->Read(&response));
189
190   auto status = stream->Finish();
191   EXPECT_TRUE(status.ok());
192 }
193
194 // Wall-clock time jumps back on client before bidi stream is created
195 TEST_F(TimeChangeTest, TimeJumpBackBeforeStreamCreated) {
196   EchoRequest request;
197   EchoResponse response;
198   ClientContext context;
199   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
200   context.AddMetadata(kServerResponseStreamsToSend, "1");
201
202   auto channel = GetChannel();
203   GPR_ASSERT(channel);
204   EXPECT_TRUE(
205       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
206   auto stub = CreateStub();
207
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));
213
214   EXPECT_TRUE(stream->WritesDone());
215   EXPECT_TRUE(stream->Read(&response));
216   EXPECT_EQ(request.message(), response.message());
217
218   auto status = stream->Finish();
219   EXPECT_TRUE(status.ok());
220 }
221
222 // Wall-clock time jumps forward on client while call is in progress
223 TEST_F(TimeChangeTest, TimeJumpForwardAfterStreamCreated) {
224   EchoRequest request;
225   EchoResponse response;
226   ClientContext context;
227   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
228   context.AddMetadata(kServerResponseStreamsToSend, "2");
229
230   auto channel = GetChannel();
231   GPR_ASSERT(channel);
232   EXPECT_TRUE(
233       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
234   auto stub = CreateStub();
235
236   auto stream = stub->BidiStream(&context);
237
238   request.set_message("Hello");
239   EXPECT_TRUE(stream->Write(request));
240   EXPECT_TRUE(stream->Read(&response));
241
242   // time jumps forward by TIME_OFFSET1 milliseconds.
243   set_now_offset(TIME_OFFSET1);
244
245   request.set_message("World");
246   EXPECT_TRUE(stream->Write(request));
247   EXPECT_TRUE(stream->WritesDone());
248   EXPECT_TRUE(stream->Read(&response));
249
250   auto status = stream->Finish();
251   EXPECT_TRUE(status.ok());
252 }
253
254 // Wall-clock time jumps back on client while call is in progress
255 TEST_F(TimeChangeTest, TimeJumpBackAfterStreamCreated) {
256   EchoRequest request;
257   EchoResponse response;
258   ClientContext context;
259   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
260   context.AddMetadata(kServerResponseStreamsToSend, "2");
261
262   auto channel = GetChannel();
263   GPR_ASSERT(channel);
264   EXPECT_TRUE(
265       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
266   auto stub = CreateStub();
267
268   auto stream = stub->BidiStream(&context);
269
270   request.set_message("Hello");
271   EXPECT_TRUE(stream->Write(request));
272   EXPECT_TRUE(stream->Read(&response));
273
274   // time jumps back TIME_OFFSET1 milliseconds.
275   set_now_offset(-TIME_OFFSET1);
276
277   request.set_message("World");
278   EXPECT_TRUE(stream->Write(request));
279   EXPECT_TRUE(stream->WritesDone());
280   EXPECT_TRUE(stream->Read(&response));
281
282   auto status = stream->Finish();
283   EXPECT_TRUE(status.ok());
284 }
285
286 // Wall-clock time jumps forward on client before connection to server is up
287 TEST_F(TimeChangeTest, TimeJumpForwardBeforeServerConnect) {
288   EchoRequest request;
289   EchoResponse response;
290   ClientContext context;
291   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
292   context.AddMetadata(kServerResponseStreamsToSend, "2");
293
294   auto channel = GetChannel();
295   GPR_ASSERT(channel);
296
297   // time jumps forward by TIME_OFFSET2 milliseconds
298   set_now_offset(TIME_OFFSET2);
299
300   auto ret =
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
305 #ifdef GPR_LINUX
306   EXPECT_TRUE(ret);
307   auto stub = CreateStub();
308   auto stream = stub->BidiStream(&context);
309
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));
317
318   auto status = stream->Finish();
319   EXPECT_TRUE(status.ok());
320 #else
321   EXPECT_FALSE(ret);
322 #endif
323 }
324
325 // Wall-clock time jumps back on client before connection to server is up
326 TEST_F(TimeChangeTest, TimeJumpBackBeforeServerConnect) {
327   EchoRequest request;
328   EchoResponse response;
329   ClientContext context;
330   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
331   context.AddMetadata(kServerResponseStreamsToSend, "2");
332
333   auto channel = GetChannel();
334   GPR_ASSERT(channel);
335
336   // time jumps back by TIME_OFFSET2 milliseconds
337   set_now_offset(-TIME_OFFSET2);
338
339   EXPECT_TRUE(
340       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
341   auto stub = CreateStub();
342   auto stream = stub->BidiStream(&context);
343
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));
351
352   auto status = stream->Finish();
353   EXPECT_TRUE(status.ok());
354 }
355
356 // Wall-clock time jumps forward and backwards during call
357 TEST_F(TimeChangeTest, TimeJumpForwardAndBackDuringCall) {
358   EchoRequest request;
359   EchoResponse response;
360   ClientContext context;
361   context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
362   context.AddMetadata(kServerResponseStreamsToSend, "2");
363
364   auto channel = GetChannel();
365   GPR_ASSERT(channel);
366
367   EXPECT_TRUE(
368       channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
369   auto stub = CreateStub();
370   auto stream = stub->BidiStream(&context);
371
372   request.set_message("Hello");
373   EXPECT_TRUE(stream->Write(request));
374
375   // time jumps back by TIME_OFFSET2 milliseconds
376   set_now_offset(-TIME_OFFSET2);
377
378   EXPECT_TRUE(stream->Read(&response));
379   request.set_message("World");
380
381   // time jumps forward by TIME_OFFSET milliseconds
382   set_now_offset(TIME_OFFSET1);
383
384   EXPECT_TRUE(stream->Write(request));
385
386   // time jumps back by TIME_OFFSET2 milliseconds
387   set_now_offset(-TIME_OFFSET2);
388
389   EXPECT_TRUE(stream->WritesDone());
390
391   // time jumps back by TIME_OFFSET2 milliseconds
392   set_now_offset(-TIME_OFFSET2);
393
394   EXPECT_TRUE(stream->Read(&response));
395
396   // time jumps back by TIME_OFFSET2 milliseconds
397   set_now_offset(-TIME_OFFSET2);
398
399   auto status = stream->Finish();
400   EXPECT_TRUE(status.ok());
401 }
402
403 }  // namespace
404
405 }  // namespace testing
406 }  // namespace grpc
407
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);
415   } else {
416     g_root = ".";
417   }
418
419   gpr_mu_init(&g_mu);
420   gpr_now_impl = now_impl;
421
422   grpc::testing::TestEnvironment env(argc, argv);
423   ::testing::InitGoogleTest(&argc, argv);
424   auto ret = RUN_ALL_TESTS();
425   return ret;
426 }