• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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