time_change_test.cc
Go to the documentation of this file.
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 <sys/time.h>
20 
21 #include <thread>
22 
23 #include <gtest/gtest.h>
24 
25 #include "absl/memory/memory.h"
26 
27 #include <grpc/grpc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/time.h>
30 #include <grpcpp/channel.h>
31 #include <grpcpp/client_context.h>
32 #include <grpcpp/create_channel.h>
33 #include <grpcpp/server.h>
34 #include <grpcpp/server_builder.h>
35 #include <grpcpp/server_context.h>
36 
38 #include "src/proto/grpc/testing/echo.grpc.pb.h"
39 #include "test/core/util/port.h"
43 
44 using grpc::testing::EchoRequest;
45 using grpc::testing::EchoResponse;
46 
48 
49 static gpr_mu g_mu;
50 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
52 static int g_time_shift_sec = 0;
53 static int g_time_shift_nsec = 0;
55  auto ts = gpr_now_impl_orig(clock);
56  // We only manipulate the realtime clock to simulate changes in wall-clock
57  // time
58  if (clock != GPR_CLOCK_REALTIME) {
59  return ts;
60  }
61  GPR_ASSERT(ts.tv_nsec >= 0);
62  GPR_ASSERT(ts.tv_nsec < GPR_NS_PER_SEC);
63  gpr_mu_lock(&g_mu);
64  ts.tv_sec += g_time_shift_sec;
65  ts.tv_nsec += g_time_shift_nsec;
67  if (ts.tv_nsec >= GPR_NS_PER_SEC) {
68  ts.tv_nsec -= GPR_NS_PER_SEC;
69  ++ts.tv_sec;
70  } else if (ts.tv_nsec < 0) {
71  --ts.tv_sec;
72  ts.tv_nsec = GPR_NS_PER_SEC + ts.tv_nsec;
73  }
74  return ts;
75 }
76 
77 // offset the value returned by gpr_now(GPR_CLOCK_REALTIME) by msecs
78 // milliseconds
79 static void set_now_offset(int msecs) {
80  gpr_mu_lock(&g_mu);
81  g_time_shift_sec = msecs / 1000;
82  g_time_shift_nsec = (msecs % 1000) * 1e6;
84 }
85 
86 // restore the original implementation of gpr_now()
87 static void reset_now_offset() {
88  gpr_mu_lock(&g_mu);
89  g_time_shift_sec = 0;
92 }
93 
94 namespace grpc {
95 namespace testing {
96 
97 namespace {
98 
99 // gpr_now() is called with invalid clock_type
100 TEST(TimespecTest, GprNowInvalidClockType) {
101  // initialize to some junk value
102  gpr_clock_type invalid_clock_type = static_cast<gpr_clock_type>(32641);
103  EXPECT_DEATH(gpr_now(invalid_clock_type), ".*");
104 }
105 
106 // Add timespan with negative nanoseconds
107 TEST(TimespecTest, GprTimeAddNegativeNs) {
109  gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
110  EXPECT_DEATH(gpr_time_add(now, bad_ts), ".*");
111 }
112 
113 // Subtract timespan with negative nanoseconds
114 TEST(TimespecTest, GprTimeSubNegativeNs) {
115  // Nanoseconds must always be positive. Negative timestamps are represented by
116  // (negative seconds, positive nanoseconds)
118  gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
119  EXPECT_DEATH(gpr_time_sub(now, bad_ts), ".*");
120 }
121 
122 // Add negative milliseconds to gpr_timespec
123 TEST(TimespecTest, GrpcNegativeMillisToTimespec) {
124  // -1500 milliseconds converts to timespec (-2 secs, 5 * 10^8 nsec)
125  gpr_timespec ts =
128  GPR_ASSERT(ts.tv_sec = -2);
129  GPR_ASSERT(ts.tv_nsec = 5e8);
131 }
132 
133 class TimeChangeTest : public ::testing::Test {
134  protected:
135  TimeChangeTest() {}
136 
137  static void SetUpTestCase() {
139  std::ostringstream addr_stream;
140  addr_stream << "localhost:" << port;
141  server_address_ = addr_stream.str();
142  server_ = absl::make_unique<SubProcess>(std::vector<std::string>({
143  g_root + "/client_crash_test_server",
144  "--address=" + server_address_,
145  }));
147  // connect to server and make sure it's reachable.
148  auto channel =
151  EXPECT_TRUE(channel->WaitForConnected(
153  }
154 
155  static void TearDownTestCase() { server_.reset(); }
156 
157  void SetUp() override {
158  channel_ =
161  stub_ = grpc::testing::EchoTestService::NewStub(channel_);
162  }
163 
164  void TearDown() override { reset_now_offset(); }
165 
166  std::unique_ptr<grpc::testing::EchoTestService::Stub> CreateStub() {
167  return grpc::testing::EchoTestService::NewStub(channel_);
168  }
169 
170  std::shared_ptr<Channel> GetChannel() { return channel_; }
171  // time jump offsets in milliseconds
172  const int TIME_OFFSET1 = 20123;
173  const int TIME_OFFSET2 = 5678;
174 
175  private:
177  static std::unique_ptr<SubProcess> server_;
178  std::shared_ptr<Channel> channel_;
179  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
180 };
182 std::unique_ptr<SubProcess> TimeChangeTest::server_;
183 
184 // Wall-clock time jumps forward on client before bidi stream is created
185 TEST_F(TimeChangeTest, TimeJumpForwardBeforeStreamCreated) {
186  EchoRequest request;
187  EchoResponse response;
188  ClientContext context;
191 
192  auto channel = GetChannel();
194  EXPECT_TRUE(
195  channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
196  auto stub = CreateStub();
197 
198  // time jumps forward by TIME_OFFSET1 milliseconds
200  auto stream = stub->BidiStream(&context);
201  request.set_message("Hello");
202  EXPECT_TRUE(stream->Write(request));
203 
204  EXPECT_TRUE(stream->WritesDone());
205  EXPECT_TRUE(stream->Read(&response));
206 
207  auto status = stream->Finish();
208  EXPECT_TRUE(status.ok());
209 }
210 
211 // Wall-clock time jumps back on client before bidi stream is created
212 TEST_F(TimeChangeTest, TimeJumpBackBeforeStreamCreated) {
213  EchoRequest request;
214  EchoResponse response;
215  ClientContext context;
218 
219  auto channel = GetChannel();
221  EXPECT_TRUE(
222  channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
223  auto stub = CreateStub();
224 
225  // time jumps back by TIME_OFFSET1 milliseconds
227  auto stream = stub->BidiStream(&context);
228  request.set_message("Hello");
229  EXPECT_TRUE(stream->Write(request));
230 
231  EXPECT_TRUE(stream->WritesDone());
232  EXPECT_TRUE(stream->Read(&response));
233  EXPECT_EQ(request.message(), response.message());
234 
235  auto status = stream->Finish();
236  EXPECT_TRUE(status.ok());
237 }
238 
239 // Wall-clock time jumps forward on client while call is in progress
240 TEST_F(TimeChangeTest, TimeJumpForwardAfterStreamCreated) {
241  EchoRequest request;
242  EchoResponse response;
243  ClientContext context;
246 
247  auto channel = GetChannel();
249  EXPECT_TRUE(
250  channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
251  auto stub = CreateStub();
252 
253  auto stream = stub->BidiStream(&context);
254 
255  request.set_message("Hello");
256  EXPECT_TRUE(stream->Write(request));
257  EXPECT_TRUE(stream->Read(&response));
258 
259  // time jumps forward by TIME_OFFSET1 milliseconds.
261 
262  request.set_message("World");
263  EXPECT_TRUE(stream->Write(request));
264  EXPECT_TRUE(stream->WritesDone());
265  EXPECT_TRUE(stream->Read(&response));
266 
267  auto status = stream->Finish();
268  EXPECT_TRUE(status.ok());
269 }
270 
271 // Wall-clock time jumps back on client while call is in progress
272 TEST_F(TimeChangeTest, TimeJumpBackAfterStreamCreated) {
273  EchoRequest request;
274  EchoResponse response;
275  ClientContext context;
278 
279  auto channel = GetChannel();
281  EXPECT_TRUE(
282  channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
283  auto stub = CreateStub();
284 
285  auto stream = stub->BidiStream(&context);
286 
287  request.set_message("Hello");
288  EXPECT_TRUE(stream->Write(request));
289  EXPECT_TRUE(stream->Read(&response));
290 
291  // time jumps back TIME_OFFSET1 milliseconds.
293 
294  request.set_message("World");
295  EXPECT_TRUE(stream->Write(request));
296  EXPECT_TRUE(stream->WritesDone());
297  EXPECT_TRUE(stream->Read(&response));
298 
299  auto status = stream->Finish();
300  EXPECT_TRUE(status.ok());
301 }
302 
303 // Wall-clock time jumps forward and backwards during call
304 TEST_F(TimeChangeTest, TimeJumpForwardAndBackDuringCall) {
305  EchoRequest request;
306  EchoResponse response;
307  ClientContext context;
310 
311  auto channel = GetChannel();
313 
314  EXPECT_TRUE(
315  channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
316  auto stub = CreateStub();
317  auto stream = stub->BidiStream(&context);
318 
319  request.set_message("Hello");
320  EXPECT_TRUE(stream->Write(request));
321 
322  // time jumps back by TIME_OFFSET2 milliseconds
324 
325  EXPECT_TRUE(stream->Read(&response));
326  request.set_message("World");
327 
328  // time jumps forward by TIME_OFFSET milliseconds
330 
331  EXPECT_TRUE(stream->Write(request));
332 
333  // time jumps back by TIME_OFFSET2 milliseconds
335 
336  EXPECT_TRUE(stream->WritesDone());
337 
338  // time jumps back by TIME_OFFSET2 milliseconds
340 
341  EXPECT_TRUE(stream->Read(&response));
342 
343  // time jumps back by TIME_OFFSET2 milliseconds
345 
346  auto status = stream->Finish();
347  EXPECT_TRUE(status.ok());
348 }
349 
350 } // namespace
351 
352 } // namespace testing
353 } // namespace grpc
354 
355 int main(int argc, char** argv) {
356  std::string me = argv[0];
357  // get index of last slash in path to test binary
358  auto lslash = me.rfind('/');
359  // set g_root = path to directory containing test binary
360  if (lslash != std::string::npos) {
361  g_root = me.substr(0, lslash);
362  } else {
363  g_root = ".";
364  }
365 
366  gpr_mu_init(&g_mu);
368 
369  grpc::testing::TestEnvironment env(&argc, argv);
370  ::testing::InitGoogleTest(&argc, argv);
371  auto ret = RUN_ALL_TESTS();
372  return ret;
373 }
gpr_timespec::tv_nsec
int32_t tv_nsec
Definition: gpr_types.h:52
GPR_TIMESPAN
@ GPR_TIMESPAN
Definition: gpr_types.h:45
gpr_timespec::tv_sec
int64_t tv_sec
Definition: gpr_types.h:51
testing
Definition: aws_request_signer_test.cc:25
grpc::status
auto status
Definition: cpp/client/credentials_test.cc:200
gpr_mu_unlock
GPRAPI void gpr_mu_unlock(gpr_mu *mu)
now
static double now(void)
Definition: test/core/fling/client.cc:130
log.h
port.h
generate.env
env
Definition: generate.py:37
grpc
Definition: grpcpp/alarm.h:33
benchmark.request
request
Definition: benchmark.py:77
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
grpc::ClientContext::set_deadline
void set_deadline(const T &deadline)
Definition: grpcpp/impl/codegen/client_context.h:274
gpr_now_impl_orig
gpr_timespec(* gpr_now_impl_orig)(gpr_clock_type clock_type)
Definition: time_change_test.cc:51
server_address_
static std::string server_address_
Definition: time_change_test.cc:176
time.h
async_greeter_client.stub
stub
Definition: hellostreamingworld/async_greeter_client.py:26
reset_now_offset
static void reset_now_offset()
Definition: time_change_test.cc:87
GPR_NS_PER_SEC
#define GPR_NS_PER_SEC
Definition: include/grpc/support/time.h:41
grpc::ClientContext::AddMetadata
void AddMetadata(const std::string &meta_key, const std::string &meta_value)
Definition: client_context.cc:121
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
test_service_impl.h
subprocess.h
channel
wrapped_grpc_channel * channel
Definition: src/php/ext/grpc/call.h:33
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
channel_
std::shared_ptr< Channel > channel_
Definition: time_change_test.cc:178
gpr_time_sub
GPRAPI gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:168
grpc_timeout_milliseconds_to_deadline
gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms)
Definition: test/core/util/test_config.cc:89
gpr_mu_init
GPRAPI void gpr_mu_init(gpr_mu *mu)
now_impl
static gpr_timespec now_impl(gpr_clock_type clock)
Definition: time_change_test.cc:54
grpc::testing::kServerResponseStreamsToSend
const char *const kServerResponseStreamsToSend
Definition: test_service_impl.h:43
grpc.h
TIME_OFFSET2
const int TIME_OFFSET2
Definition: time_change_test.cc:173
channel.h
gpr_now_impl
gpr_timespec(* gpr_now_impl)(gpr_clock_type clock_type)
GPR_CLOCK_MONOTONIC
@ GPR_CLOCK_MONOTONIC
Definition: gpr_types.h:36
gpr_mu_lock
GPRAPI void gpr_mu_lock(gpr_mu *mu)
grpc::CreateChannel
std::shared_ptr< Channel > CreateChannel(const grpc::string &target, const std::shared_ptr< ChannelCredentials > &creds)
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
grpc_pick_unused_port_or_die
int grpc_pick_unused_port_or_die(void)
gpr_now
GPRAPI gpr_timespec gpr_now(gpr_clock_type clock)
grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch
static constexpr Timestamp FromMillisecondsAfterProcessEpoch(int64_t millis)
Definition: src/core/lib/gprpp/time.h:73
stub_
std::unique_ptr< grpc::testing::EchoTestService::Stub > stub_
Definition: time_change_test.cc:179
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
gpr_timespec::clock_type
gpr_clock_type clock_type
Definition: gpr_types.h:55
g_root
static std::string g_root
Definition: time_change_test.cc:47
test_config.h
g_time_shift_nsec
static int g_time_shift_nsec
Definition: time_change_test.cc:53
client_context.h
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
grpc::testing::TEST_F
TEST_F(ChannelArgumentsTest, SetInt)
Definition: channel_arguments_test.cc:134
gpr_time_add
GPRAPI gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:135
gpr_mu
pthread_mutex_t gpr_mu
Definition: impl/codegen/sync_posix.h:47
gpr_timespec
struct gpr_timespec gpr_timespec
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
server_
static std::unique_ptr< SubProcess > server_
Definition: time_change_test.cc:177
server_context.h
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
g_time_shift_sec
static int g_time_shift_sec
Definition: time_change_test.cc:52
g_mu
static gpr_mu g_mu
Definition: time_change_test.cc:49
grpc::testing::EXPECT_EQ
EXPECT_EQ(options.token_exchange_service_uri, "https://foo/exchange")
timer.h
grpc::testing::TEST
TEST(StatsTest, IncCounters)
Definition: stats_test.cc:51
context
grpc::ClientContext context
Definition: istio_echo_server_lib.cc:61
grpc::testing::EXPECT_TRUE
EXPECT_TRUE(grpc::experimental::StsCredentialsOptionsFromJson(minimum_valid_json, &options) .ok())
server.h
gpr_timespec
Definition: gpr_types.h:50
grpc::InsecureChannelCredentials
std::shared_ptr< ChannelCredentials > InsecureChannelCredentials()
Credentials for an unencrypted, unauthenticated channel.
Definition: cpp/client/insecure_credentials.cc:69
GPR_CLOCK_REALTIME
@ GPR_CLOCK_REALTIME
Definition: gpr_types.h:39
TIME_OFFSET1
const int TIME_OFFSET1
Definition: time_change_test.cc:172
set_now_offset
static void set_now_offset(int msecs)
Definition: time_change_test.cc:79
server_builder.h
grpc_core::Timestamp::as_timespec
gpr_timespec as_timespec(gpr_clock_type type) const
Definition: src/core/lib/gprpp/time.cc:157
main
int main(int argc, char **argv)
Definition: time_change_test.cc:355
create_channel.h
gpr_clock_type
gpr_clock_type
Definition: gpr_types.h:34
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:37