xref: /aosp_15_r20/external/grpc-grpc/test/cpp/common/timer_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 "src/core/lib/iomgr/timer.h"
20 
21 #include <gtest/gtest.h>
22 
23 #include <grpc/grpc.h>
24 #include <grpc/support/log.h>
25 
26 #include "src/core/lib/gprpp/crash.h"
27 #include "src/core/lib/gprpp/time.h"
28 #include "src/core/lib/iomgr/closure.h"
29 #include "src/core/lib/iomgr/error.h"
30 #include "src/core/lib/iomgr/exec_ctx.h"
31 #include "src/core/lib/iomgr/timer_manager.h"
32 #include "test/core/util/test_config.h"
33 
34 #ifdef GRPC_POSIX_SOCKET_EV
35 #include "src/core/lib/iomgr/ev_posix.h"
36 #endif
37 
38 // MAYBE_SKIP_TEST is a macro to determine if this particular test configuration
39 // should be skipped based on a decision made at SetUp time.
40 #define MAYBE_SKIP_TEST \
41   do {                  \
42     if (do_not_test_) { \
43       return;           \
44     }                   \
45   } while (0)
46 
47 class TimerTest : public ::testing::Test {
48  protected:
SetUp()49   void SetUp() override {
50     grpc_init();
51     // Skip test if slowdown factor > 1, or we are
52     // using event manager.
53 #ifdef GRPC_POSIX_SOCKET_EV
54     if (grpc_test_slowdown_factor() != 1 ||
55         grpc_event_engine_run_in_background()) {
56 #else
57     if (grpc_test_slowdown_factor() != 1) {
58 #endif
59       do_not_test_ = true;
60     }
61   }
62 
63   void TearDown() override { grpc_shutdown(); }
64 
65   bool do_not_test_{false};
66 };
67 
68 #ifndef GPR_WINDOWS
69 // the test fails with too many wakeups on windows opt build
70 // the mechanism by which that happens is described in
71 // https://github.com/grpc/grpc/issues/20436
TEST_F(TimerTest,NoTimers)72 TEST_F(TimerTest, NoTimers) {
73   MAYBE_SKIP_TEST;
74   grpc_core::ExecCtx exec_ctx;
75   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
76 
77   // We expect to get 1 wakeup per second. Sometimes we also get a wakeup
78   // during initialization, so in 1.5 seconds we expect to get 1 or 2 wakeups.
79   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
80   GPR_ASSERT(wakeups == 1 || wakeups == 2);
81 }
82 #endif
83 
TEST_F(TimerTest,OneTimerExpires)84 TEST_F(TimerTest, OneTimerExpires) {
85   MAYBE_SKIP_TEST;
86   grpc_core::ExecCtx exec_ctx;
87   grpc_timer timer;
88   int timer_fired = 0;
89   grpc_timer_init(
90       &timer,
91       grpc_core::Timestamp::Now() + grpc_core::Duration::Milliseconds(500),
92       GRPC_CLOSURE_CREATE(
93           [](void* arg, grpc_error_handle) {
94             int* timer_fired = static_cast<int*>(arg);
95             ++*timer_fired;
96           },
97           &timer_fired, grpc_schedule_on_exec_ctx));
98   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
99   GPR_ASSERT(1 == timer_fired);
100 
101   // We expect to get 1 wakeup/second + 1 wakeup for the expired timer + maybe 1
102   // wakeup during initialization. i.e. in 1.5 seconds we expect 2 or 3 wakeups.
103   // Actual number of wakeups is more due to bug
104   // https://github.com/grpc/grpc/issues/19947
105   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
106   gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
107 }
108 
TEST_F(TimerTest,MultipleTimersExpire)109 TEST_F(TimerTest, MultipleTimersExpire) {
110   MAYBE_SKIP_TEST;
111   grpc_core::ExecCtx exec_ctx;
112   const int kNumTimers = 10;
113   grpc_timer timers[kNumTimers];
114   int timer_fired = 0;
115   for (int i = 0; i < kNumTimers; ++i) {
116     grpc_timer_init(&timers[i],
117                     grpc_core::Timestamp::Now() +
118                         grpc_core::Duration::Milliseconds(500) +
119                         grpc_core::Duration::Milliseconds(i),
120                     GRPC_CLOSURE_CREATE(
121                         [](void* arg, grpc_error_handle) {
122                           int* timer_fired = static_cast<int*>(arg);
123                           ++*timer_fired;
124                         },
125                         &timer_fired, grpc_schedule_on_exec_ctx));
126   }
127 
128   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
129   GPR_ASSERT(kNumTimers == timer_fired);
130 
131   // We expect to get 1 wakeup/second + 1 wakeup for per timer fired + maybe 1
132   // wakeup during initialization. i.e. in 1.5 seconds we expect 11 or 12
133   // wakeups. Actual number of wakeups is more due to bug
134   // https://github.com/grpc/grpc/issues/19947
135   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
136   gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
137 }
138 
TEST_F(TimerTest,CancelSomeTimers)139 TEST_F(TimerTest, CancelSomeTimers) {
140   MAYBE_SKIP_TEST;
141   grpc_core::ExecCtx exec_ctx;
142   const int kNumTimers = 10;
143   grpc_timer timers[kNumTimers];
144   std::atomic<int> timer_fired{0};
145   grpc_core::ExecCtx::Get()->InvalidateNow();
146   for (int i = 0; i < kNumTimers; ++i) {
147     // Set a large firing time for timers which are bound to be cancelled
148     // and set a small firing time for timers which need to execute.
149     grpc_timer_init(
150         &timers[i],
151         grpc_core::Timestamp::Now() +
152             ((i < kNumTimers / 2) ? grpc_core ::Duration::Milliseconds(60000)
153                                   : grpc_core ::Duration::Milliseconds(100) +
154                                         grpc_core::Duration::Milliseconds(i)),
155         GRPC_CLOSURE_CREATE(
156             [](void* arg, grpc_error_handle error) {
157               if (error == absl::CancelledError()) {
158                 return;
159               }
160               std::atomic<int>* timer_fired =
161                   static_cast<std::atomic<int>*>(arg);
162               ++*timer_fired;
163             },
164             &timer_fired, grpc_schedule_on_exec_ctx));
165   }
166   for (int i = 0; i < kNumTimers / 2; ++i) {
167     grpc_timer_cancel(&timers[i]);
168   }
169 
170   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
171   GPR_ASSERT(kNumTimers / 2 == timer_fired);
172 
173   // We expect to get 1 wakeup/second + 1 wakeup per timer fired + maybe 1
174   // wakeup during initialization. i.e. in 1.5 seconds we expect 6 or 7 wakeups.
175   // Actual number of wakeups is more due to bug
176   // https://github.com/grpc/grpc/issues/19947
177   int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
178   gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
179 }
180 
181 // Enable the following test after
182 // https://github.com/grpc/grpc/issues/20049 has been fixed.
TEST_F(TimerTest,DISABLED_TimerNotCanceled)183 TEST_F(TimerTest, DISABLED_TimerNotCanceled) {
184   grpc_core::ExecCtx exec_ctx;
185   grpc_timer timer;
186   grpc_timer_init(
187       &timer, grpc_core::Timestamp::Now() + grpc_core::Duration::Seconds(10),
188       GRPC_CLOSURE_CREATE([](void*, grpc_error_handle) {}, nullptr,
189                           grpc_schedule_on_exec_ctx));
190 }
191 
192 // Enable the following test after
193 // https://github.com/grpc/grpc/issues/20064 has been fixed.
TEST_F(TimerTest,DISABLED_CancelRace)194 TEST_F(TimerTest, DISABLED_CancelRace) {
195   MAYBE_SKIP_TEST;
196   grpc_core::ExecCtx exec_ctx;
197   const int kNumTimers = 10;
198   grpc_timer timers[kNumTimers];
199   for (int i = 0; i < kNumTimers; ++i) {
200     grpc_timer* arg = (i != 0) ? &timers[i - 1] : nullptr;
201     grpc_timer_init(
202         &timers[i],
203         grpc_core::Timestamp::Now() + grpc_core::Duration::Milliseconds(100),
204         GRPC_CLOSURE_CREATE(
205             [](void* arg, grpc_error_handle /*error*/) {
206               grpc_timer* timer = static_cast<grpc_timer*>(arg);
207               if (timer) {
208                 grpc_timer_cancel(timer);
209               }
210             },
211             arg, grpc_schedule_on_exec_ctx));
212   }
213   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
214 }
215 
216 // Enable the following test after
217 // https://github.com/grpc/grpc/issues/20066 has been fixed.
TEST_F(TimerTest,DISABLED_CancelNextTimer)218 TEST_F(TimerTest, DISABLED_CancelNextTimer) {
219   MAYBE_SKIP_TEST;
220   grpc_core::ExecCtx exec_ctx;
221   const int kNumTimers = 10;
222   grpc_timer timers[kNumTimers];
223 
224   for (int i = 0; i < kNumTimers; ++i) {
225     grpc_timer_init_unset(&timers[i]);
226   }
227 
228   for (int i = 0; i < kNumTimers; ++i) {
229     grpc_timer* arg = nullptr;
230     if (i < kNumTimers - 1) {
231       arg = &timers[i + 1];
232     }
233     grpc_timer_init(
234         &timers[i],
235         grpc_core::Timestamp::Now() + grpc_core::Duration::Milliseconds(100),
236         GRPC_CLOSURE_CREATE(
237             [](void* arg, grpc_error_handle /*error*/) {
238               grpc_timer* timer = static_cast<grpc_timer*>(arg);
239               if (timer) {
240                 grpc_timer_cancel(timer);
241               }
242             },
243             arg, grpc_schedule_on_exec_ctx));
244   }
245   grpc_timer_cancel(&timers[0]);
246   gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
247 }
248 
main(int argc,char ** argv)249 int main(int argc, char** argv) {
250   grpc::testing::TestEnvironment env(&argc, argv);
251   ::testing::InitGoogleTest(&argc, argv);
252   return RUN_ALL_TESTS();
253 }
254