xref: /aosp_15_r20/external/federated-compute/fcp/base/simulated_clock_test.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
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