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