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