• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 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 <grpc/event_engine/event_engine.h>
20 #include <grpc/support/time.h>
21 
22 #include <cstdint>
23 #include <limits>
24 #include <vector>
25 
26 #include "absl/types/optional.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "src/core/lib/event_engine/posix_engine/timer.h"
30 #include "src/core/util/time.h"
31 
32 using testing::Mock;
33 using testing::Return;
34 using testing::StrictMock;
35 
36 namespace grpc_event_engine {
37 namespace experimental {
38 
39 namespace {
40 const int64_t kHoursIn25Days = 25 * 24;
41 const grpc_core::Duration k25Days = grpc_core::Duration::Hours(kHoursIn25Days);
42 
43 class MockClosure : public experimental::EventEngine::Closure {
44  public:
45   MOCK_METHOD(void, Run, ());
46 };
47 
48 class MockHost : public TimerListHost {
49  public:
~MockHost()50   virtual ~MockHost() {}
51   MOCK_METHOD(grpc_core::Timestamp, Now, ());
52   MOCK_METHOD(void, Kick, ());
53 };
54 
55 enum class CheckResult { kTimersFired, kCheckedAndEmpty, kNotChecked };
56 
FinishCheck(absl::optional<std::vector<experimental::EventEngine::Closure * >> result)57 CheckResult FinishCheck(
58     absl::optional<std::vector<experimental::EventEngine::Closure*>> result) {
59   if (!result.has_value()) return CheckResult::kNotChecked;
60   if (result->empty()) return CheckResult::kCheckedAndEmpty;
61   for (auto closure : *result) {
62     closure->Run();
63   }
64   return CheckResult::kTimersFired;
65 }
66 
67 }  // namespace
68 
TEST(TimerListTest,Add)69 TEST(TimerListTest, Add) {
70   Timer timers[20];
71   StrictMock<MockClosure> closures[20];
72 
73   const auto kStart =
74       grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(100);
75 
76   StrictMock<MockHost> host;
77   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
78   TimerList timer_list(&host);
79 
80   // 10 ms timers.  will expire in the current epoch
81   for (int i = 0; i < 10; i++) {
82     EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
83     timer_list.TimerInit(&timers[i],
84                          kStart + grpc_core::Duration::Milliseconds(10),
85                          &closures[i]);
86   }
87 
88   // 1010 ms timers.  will expire in the next epoch
89   for (int i = 10; i < 20; i++) {
90     EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
91     timer_list.TimerInit(&timers[i],
92                          kStart + grpc_core::Duration::Milliseconds(1010),
93                          &closures[i]);
94   }
95 
96   // collect timers.  Only the first batch should be ready.
97   EXPECT_CALL(host, Now())
98       .WillOnce(Return(kStart + grpc_core::Duration::Milliseconds(500)));
99   for (int i = 0; i < 10; i++) {
100     EXPECT_CALL(closures[i], Run());
101   }
102   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
103             CheckResult::kTimersFired);
104   for (int i = 0; i < 10; i++) {
105     Mock::VerifyAndClearExpectations(&closures[i]);
106   }
107 
108   EXPECT_CALL(host, Now())
109       .WillOnce(Return(kStart + grpc_core::Duration::Milliseconds(600)));
110   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
111             CheckResult::kCheckedAndEmpty);
112 
113   // collect the rest of the timers
114   EXPECT_CALL(host, Now())
115       .WillOnce(Return(kStart + grpc_core::Duration::Milliseconds(1500)));
116   for (int i = 10; i < 20; i++) {
117     EXPECT_CALL(closures[i], Run());
118   }
119   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
120             CheckResult::kTimersFired);
121   for (int i = 10; i < 20; i++) {
122     Mock::VerifyAndClearExpectations(&closures[i]);
123   }
124 
125   EXPECT_CALL(host, Now())
126       .WillOnce(Return(kStart + grpc_core::Duration::Milliseconds(1600)));
127   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
128             CheckResult::kCheckedAndEmpty);
129 }
130 
131 // Cleaning up a list with pending timers.
TEST(TimerListTest,Destruction)132 TEST(TimerListTest, Destruction) {
133   Timer timers[5];
134   StrictMock<MockClosure> closures[5];
135 
136   StrictMock<MockHost> host;
137   EXPECT_CALL(host, Now())
138       .WillOnce(
139           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
140   TimerList timer_list(&host);
141 
142   EXPECT_CALL(host, Now())
143       .WillOnce(
144           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
145   timer_list.TimerInit(
146       &timers[0], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(100),
147       &closures[0]);
148   EXPECT_CALL(host, Now())
149       .WillOnce(
150           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
151   timer_list.TimerInit(
152       &timers[1], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(3),
153       &closures[1]);
154   EXPECT_CALL(host, Now())
155       .WillOnce(
156           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
157   timer_list.TimerInit(
158       &timers[2], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(100),
159       &closures[2]);
160   EXPECT_CALL(host, Now())
161       .WillOnce(
162           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
163   timer_list.TimerInit(
164       &timers[3], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(3),
165       &closures[3]);
166   EXPECT_CALL(host, Now())
167       .WillOnce(
168           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0)));
169   timer_list.TimerInit(
170       &timers[4], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(1),
171       &closures[4]);
172   EXPECT_CALL(host, Now())
173       .WillOnce(
174           Return(grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(2)));
175   EXPECT_CALL(closures[4], Run());
176   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
177             CheckResult::kTimersFired);
178   Mock::VerifyAndClearExpectations(&closures[4]);
179   EXPECT_FALSE(timer_list.TimerCancel(&timers[4]));
180   EXPECT_TRUE(timer_list.TimerCancel(&timers[0]));
181   EXPECT_TRUE(timer_list.TimerCancel(&timers[3]));
182   EXPECT_TRUE(timer_list.TimerCancel(&timers[1]));
183   EXPECT_TRUE(timer_list.TimerCancel(&timers[2]));
184 }
185 
186 // Cleans up a list with pending timers that simulate long-running-services.
187 // This test does the following:
188 //  1) Simulates grpc server start time to 25 days in the past (completed in
189 //      `main` using TestOnlyGlobalInit())
190 //  2) Creates 4 timers - one with a deadline 25 days in the future, one just
191 //      3 milliseconds in future, one way out in the future, and one using the
192 //      Timestamp::FromTimespecRoundUp function to compute a deadline of 25
193 //      days in the future
194 //  3) Simulates 4 milliseconds of elapsed time by changing `now` (cached at
195 //      step 1) to `now+4`
196 //  4) Shuts down the timer list
197 // https://github.com/grpc/grpc/issues/15904
TEST(TimerListTest,LongRunningServiceCleanup)198 TEST(TimerListTest, LongRunningServiceCleanup) {
199   Timer timers[4];
200   StrictMock<MockClosure> closures[4];
201 
202   const auto kStart =
203       grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(k25Days.millis());
204 
205   StrictMock<MockHost> host;
206   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
207   TimerList timer_list(&host);
208 
209   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
210   timer_list.TimerInit(&timers[0], kStart + k25Days, &closures[0]);
211   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
212   timer_list.TimerInit(
213       &timers[1], kStart + grpc_core::Duration::Milliseconds(3), &closures[1]);
214   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
215   timer_list.TimerInit(&timers[2],
216                        grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
217                            std::numeric_limits<int64_t>::max() - 1),
218                        &closures[2]);
219 
220   gpr_timespec deadline_spec =
221       (kStart + k25Days).as_timespec(gpr_clock_type::GPR_CLOCK_MONOTONIC);
222 
223   // Timestamp::FromTimespecRoundUp is how users usually compute a millisecond
224   // input value into grpc_timer_init, so we mimic that behavior here
225   EXPECT_CALL(host, Now()).WillOnce(Return(kStart));
226   timer_list.TimerInit(&timers[3],
227                        grpc_core::Timestamp::FromTimespecRoundUp(deadline_spec),
228                        &closures[3]);
229 
230   EXPECT_CALL(host, Now())
231       .WillOnce(Return(kStart + grpc_core::Duration::Milliseconds(4)));
232   EXPECT_CALL(closures[1], Run());
233   EXPECT_EQ(FinishCheck(timer_list.TimerCheck(nullptr)),
234             CheckResult::kTimersFired);
235   EXPECT_TRUE(timer_list.TimerCancel(&timers[0]));
236   EXPECT_FALSE(timer_list.TimerCancel(&timers[1]));
237   EXPECT_TRUE(timer_list.TimerCancel(&timers[2]));
238   EXPECT_TRUE(timer_list.TimerCancel(&timers[3]));
239 }
240 
241 }  // namespace experimental
242 }  // namespace grpc_event_engine
243 
main(int argc,char ** argv)244 int main(int argc, char** argv) {
245   ::testing::InitGoogleTest(&argc, argv);
246   return RUN_ALL_TESTS();
247 }
248