• 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 <spawn.h>
20 #include <sstream>
21 #include <string>
22 #include <thread>
23 #include <vector>
24 
25 #include <grpc/grpc.h>
26 #include <grpc/support/log.h>
27 #include <gtest/gtest.h>
28 
29 #include "src/core/lib/gprpp/sync.h"
30 #include "src/core/lib/iomgr/closure.h"
31 #include "src/core/lib/iomgr/error.h"
32 #include "src/core/lib/iomgr/exec_ctx.h"
33 #include "src/core/lib/iomgr/timer.h"
34 #include "src/core/lib/iomgr/timer_manager.h"
35 #include "test/core/util/test_config.h"
36 
37 extern char** environ;
38 
39 #ifdef GPR_ANDROID
40 // Android doesn't have posix_spawn. Use std::system instead
run_cmd(const char * cmd)41 void run_cmd(const char* cmd) { std::system(cmd); }
42 #else
run_cmd(const char * cmd)43 void run_cmd(const char* cmd) {
44   pid_t pid;
45   const char* argv[] = {const_cast<const char*>("sh"),
46                         const_cast<const char*>("-c"), cmd, nullptr};
47   int status;
48 
49   status = posix_spawn(&pid, const_cast<const char*>("/bin/sh"), nullptr,
50                        nullptr, const_cast<char**>(argv), environ);
51   if (status == 0) {
52     if (waitpid(pid, &status, 0) == -1) {
53       perror("waitpid");
54     }
55   }
56 }
57 #endif
58 
59 class TimeJumpTest : public ::testing::TestWithParam<std::string> {
60  protected:
SetUp()61   void SetUp() override {
62     // Skip test if slowdown factor > 1
63     if (grpc_test_slowdown_factor() != 1) {
64       GTEST_SKIP();
65     } else {
66       grpc_init();
67     }
68   }
TearDown()69   void TearDown() override {
70     // Skip test if slowdown factor > 1
71     if (grpc_test_slowdown_factor() == 1) {
72       run_cmd("sudo sntp -sS pool.ntp.org");
73       grpc_shutdown_blocking();
74     }
75   }
76 
77   const int kWaitTimeMs = 1500;
78 };
79 
CreateTestScenarios()80 std::vector<std::string> CreateTestScenarios() {
81   return {"-1M", "+1M", "-1H", "+1H", "-1d", "+1d", "-1y", "+1y"};
82 }
83 INSTANTIATE_TEST_SUITE_P(TimeJump, TimeJumpTest,
84                          ::testing::ValuesIn(CreateTestScenarios()));
85 
TEST_P(TimeJumpTest,TimerRunning)86 TEST_P(TimeJumpTest, TimerRunning) {
87   grpc_core::ExecCtx exec_ctx;
88   grpc_timer timer;
89   grpc_timer_init(&timer, grpc_core::ExecCtx::Get()->Now() + 3000,
90                   GRPC_CLOSURE_CREATE(
91                       [](void*, grpc_error* error) {
92                         GPR_ASSERT(error == GRPC_ERROR_CANCELLED);
93                       },
94                       nullptr, grpc_schedule_on_exec_ctx));
95   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
96   std::ostringstream cmd;
97   cmd << "sudo date `date -v" << GetParam() << " \"+%m%d%H%M%y\"`";
98   run_cmd(cmd.str().c_str());
99   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(kWaitTimeMs));
100   // We expect 1 wakeup/sec when there are not timer expiries
101   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
102   gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
103   GPR_ASSERT(wakeups <= 3);
104   grpc_timer_cancel(&timer);
105 }
106 
TEST_P(TimeJumpTest,TimedWait)107 TEST_P(TimeJumpTest, TimedWait) {
108   grpc_core::CondVar cond;
109   grpc_core::Mutex mu;
110   {
111     grpc_core::MutexLock lock(&mu);
112     std::thread thd = std::thread([]() {
113       gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
114       std::ostringstream cmd;
115       cmd << "sudo date `date -v" << GetParam() << " \"+%m%d%H%M%y\"`";
116       run_cmd(cmd.str().c_str());
117     });
118     gpr_timespec before = gpr_now(GPR_CLOCK_MONOTONIC);
119     int timedout = cond.Wait(
120         &mu, grpc_millis_to_timespec(kWaitTimeMs, GPR_CLOCK_REALTIME));
121     gpr_timespec after = gpr_now(GPR_CLOCK_MONOTONIC);
122     int32_t elapsed_ms = gpr_time_to_millis(gpr_time_sub(after, before));
123     gpr_log(GPR_DEBUG, "After wait, timedout = %d elapsed_ms = %d", timedout,
124             elapsed_ms);
125     GPR_ASSERT(1 == timedout);
126     GPR_ASSERT(1 ==
127                gpr_time_similar(gpr_time_sub(after, before),
128                                 gpr_time_from_millis(kWaitTimeMs, GPR_TIMESPAN),
129                                 gpr_time_from_millis(50, GPR_TIMESPAN)));
130 
131     thd.join();
132   }
133   // We expect 1 wakeup/sec when there are not timer expiries
134   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
135   gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
136   GPR_ASSERT(wakeups <= 3);
137 }
138 
main(int argc,char ** argv)139 int main(int argc, char** argv) {
140   grpc::testing::TestEnvironment env(argc, argv);
141   ::testing::InitGoogleTest(&argc, argv);
142   return RUN_ALL_TESTS();
143 }
144