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