1 /*
2 * Copyright 2020 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fcp/base/simulated_clock.h"
18
19 #include <functional>
20 #include <memory>
21 #include <utility>
22 #include <vector>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/time/civil_time.h"
27 #include "absl/time/time.h"
28
29 namespace fcp {
30 namespace {
31
32 using ::testing::ElementsAre;
33 using ::testing::Eq;
34
35 // Simple callback waiter that runs the function on Wakeup.
36 class CallbackWaiter : public Clock::Waiter {
37 public:
CallbackWaiter(std::function<void ()> callback)38 explicit CallbackWaiter(std::function<void()> callback)
39 : callback_(std::move(callback)) {}
40
WakeUp()41 void WakeUp() override { callback_(); }
42
43 private:
44 std::function<void()> callback_;
45 };
46
47 // Simple test waiter that adds its ID to the provided vector when WakeUp is
48 // called. This is used to verify that waiters are woken up in the right order.
49 class TestWaiter : public CallbackWaiter {
50 public:
TestWaiter(int id,std::vector<int> * output)51 explicit TestWaiter(int id, std::vector<int>* output)
52 : CallbackWaiter([=]() { output->push_back(id); }) {}
53 };
54
GetTestInitialTime()55 absl::Time GetTestInitialTime() {
56 return absl::FromCivil(absl::CivilDay(2020, 1, 1), absl::LocalTimeZone());
57 }
58
TEST(SimulatedClockTest,GetAndUpdateNow)59 TEST(SimulatedClockTest, GetAndUpdateNow) {
60 absl::Time t = absl::UnixEpoch();
61 SimulatedClock clock;
62 EXPECT_THAT(clock.Now(), t);
63
64 absl::Time t2 = GetTestInitialTime();
65
66 SimulatedClock clock2(t2);
67 EXPECT_THAT(clock2.Now(), t2);
68
69 absl::Time t3 = t2 + absl::Seconds(42);
70 clock2.AdvanceTime(absl::Seconds(42));
71 EXPECT_THAT(clock2.Now(), t3);
72
73 absl::Time t4 = t3 + absl::Seconds(18);
74 clock2.SetTime(t4);
75 EXPECT_THAT(clock2.Now(), Eq(t4));
76 }
77
78 // Verifies that waiters with future deadlines are not triggered unless the
79 // time is advanced.
TEST(SimulatedClockTest,FutureDeadline)80 TEST(SimulatedClockTest, FutureDeadline) {
81 std::vector<int> output;
82 absl::Time t = GetTestInitialTime();
83 SimulatedClock clock(t);
84
85 clock.WakeupWithDeadline(t + absl::Seconds(1),
86 std::make_shared<TestWaiter>(1, &output));
87 EXPECT_THAT(output, ElementsAre());
88
89 clock.AdvanceTime(absl::Seconds(1));
90 EXPECT_THAT(output, ElementsAre(1));
91
92 // Advancing time again doesn't trigger the same waiter again.
93 clock.AdvanceTime(absl::Seconds(1));
94 EXPECT_THAT(output, ElementsAre(1));
95 }
96
97 // Verifies that the order of waiters with maching deadlines is preserved
98 // when their wake-up is triggered.
TEST(SimulatedClockTest,MatchingDeadlines)99 TEST(SimulatedClockTest, MatchingDeadlines) {
100 std::vector<int> output;
101 absl::Time t = GetTestInitialTime();
102 SimulatedClock clock(t);
103
104 absl::Time t1 = t + absl::Seconds(1);
105 absl::Time t2 = t + absl::Seconds(2);
106 clock.WakeupWithDeadline(t1, std::make_shared<TestWaiter>(1, &output));
107 clock.WakeupWithDeadline(t2, std::make_shared<TestWaiter>(2, &output));
108 clock.WakeupWithDeadline(t1, std::make_shared<TestWaiter>(3, &output));
109 clock.WakeupWithDeadline(t2, std::make_shared<TestWaiter>(4, &output));
110 clock.WakeupWithDeadline(t1, std::make_shared<TestWaiter>(5, &output));
111
112 // Trigger all waiters.
113 clock.AdvanceTime(absl::Seconds(2));
114 EXPECT_THAT(output, ElementsAre(1, 3, 5, 2, 4));
115 }
116
117 // Verifies that waiters with current or past deadlines are triggered promptly.
TEST(SimulatedClockTest,PastAndCurrentDeadlines)118 TEST(SimulatedClockTest, PastAndCurrentDeadlines) {
119 std::vector<int> output;
120 absl::Time t =
121 absl::FromCivil(absl::CivilDay(2020, 1, 1), absl::LocalTimeZone());
122 SimulatedClock clock(t);
123
124 clock.WakeupWithDeadline(t, std::make_shared<TestWaiter>(1, &output));
125 clock.WakeupWithDeadline(t - absl::Seconds(1),
126 std::make_shared<TestWaiter>(2, &output));
127 EXPECT_THAT(output, ElementsAre(1, 2));
128 }
129
130 // Verifies that only expired waiters are triggered.
TEST(SimulatedClockTest,MultipleWaiters)131 TEST(SimulatedClockTest, MultipleWaiters) {
132 std::vector<int> output;
133 absl::Time t = GetTestInitialTime();
134 SimulatedClock clock(t);
135
136 clock.WakeupWithDeadline(t + absl::Seconds(30),
137 std::make_shared<TestWaiter>(1, &output));
138 clock.WakeupWithDeadline(t + absl::Seconds(20),
139 std::make_shared<TestWaiter>(2, &output));
140 clock.WakeupWithDeadline(t + absl::Seconds(10),
141 std::make_shared<TestWaiter>(3, &output));
142 // Advance by 15 seconds
143 clock.AdvanceTime(absl::Seconds(15));
144 // Advance by another 5 seconds
145 clock.AdvanceTime(absl::Seconds(5));
146 // Only waiters 3 and 2 should be triggered.
147 EXPECT_THAT(output, ElementsAre(3, 2));
148 }
149
150 // Verifies that a new timer can be scheduled when anoter timer is triggered.
TEST(SimulatedClockTest,RecursiveWakeup)151 TEST(SimulatedClockTest, RecursiveWakeup) {
152 std::vector<int> output;
153 absl::Time t = GetTestInitialTime();
154 SimulatedClock clock(t);
155
156 clock.WakeupWithDeadline(t + absl::Seconds(20),
157 std::make_shared<TestWaiter>(1, &output));
158 clock.WakeupWithDeadline(
159 t + absl::Seconds(20), std::make_shared<CallbackWaiter>([&]() {
160 output.push_back(2);
161 clock.WakeupWithDeadline(t + absl::Seconds(15),
162 std::make_shared<TestWaiter>(3, &output));
163 }));
164 clock.AdvanceTime(absl::Seconds(20));
165 // Both waiters are triggered because the #3 one is already expired when
166 // inserted recursively by waiter #2.
167 EXPECT_THAT(output, ElementsAre(1, 2, 3));
168 }
169
170 // Verifies that a long taking Wakeup notification results in triggering
171 // other waiters that expire later.
TEST(SimulatedClockTest,LongRunningWakeup)172 TEST(SimulatedClockTest, LongRunningWakeup) {
173 std::vector<int> output;
174 absl::Time t = GetTestInitialTime();
175 SimulatedClock clock(t);
176
177 clock.WakeupWithDeadline(t + absl::Seconds(10),
178 std::make_shared<TestWaiter>(1, &output));
179 clock.WakeupWithDeadline(
180 t + absl::Seconds(20), std::make_shared<CallbackWaiter>([&]() {
181 output.push_back(2);
182 clock.AdvanceTime(absl::Seconds(10));
183 }));
184 clock.WakeupWithDeadline(t + absl::Seconds(30),
185 std::make_shared<TestWaiter>(3, &output));
186 // Advance time by 20 second, which will advance time by another 10 seconds
187 // when waking up waiter #2.
188 clock.AdvanceTime(absl::Seconds(20));
189 EXPECT_THAT(output, ElementsAre(1, 2, 3));
190 }
191
192 } // namespace
193 } // namespace fcp
194