xref: /aosp_15_r20/external/pigweed/pw_async2/simulated_time_provider_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_async2/simulated_time_provider.h"
16 
17 #include "pw_chrono/system_clock.h"
18 #include "pw_unit_test/framework.h"
19 
20 namespace {
21 
22 using ::pw::async2::Context;
23 using ::pw::async2::Dispatcher;
24 using ::pw::async2::Pending;
25 using ::pw::async2::Poll;
26 using ::pw::async2::Ready;
27 using ::pw::async2::SimulatedTimeProvider;
28 using ::pw::async2::Task;
29 using ::pw::async2::TimeFuture;
30 using ::pw::chrono::SystemClock;
31 using ::std::chrono_literals::operator""min;
32 using ::std::chrono_literals::operator""h;
33 
34 // We can't control the SystemClock's period configuration, so just in case
35 // 42 hours cannot be accurately expressed in integer ticks, round the
36 // duration up.
37 constexpr SystemClock::duration kRoundedArbitraryDuration =
38     SystemClock::for_at_least(42h);
39 
TEST(SimulatedTimeProvider,InitialTime)40 TEST(SimulatedTimeProvider, InitialTime) {
41   SimulatedTimeProvider<SystemClock> tp;
42 
43   EXPECT_EQ(SystemClock::time_point(SystemClock::duration(0)), tp.now());
44 }
45 
TEST(SimulatedTimeProvider,SetTime)46 TEST(SimulatedTimeProvider, SetTime) {
47   SimulatedTimeProvider<SystemClock> tp;
48 
49   tp.SetTime(SystemClock::time_point(kRoundedArbitraryDuration));
50   EXPECT_EQ(kRoundedArbitraryDuration, tp.now().time_since_epoch());
51 }
52 
TEST(SimulatedTimeProvider,AdvanceTime)53 TEST(SimulatedTimeProvider, AdvanceTime) {
54   SimulatedTimeProvider<SystemClock> tp;
55 
56   const SystemClock::time_point before_timestamp = tp.now();
57   tp.AdvanceTime(kRoundedArbitraryDuration);
58   const SystemClock::time_point after_timestamp = tp.now();
59 
60   EXPECT_EQ(kRoundedArbitraryDuration, tp.now().time_since_epoch());
61   EXPECT_EQ(kRoundedArbitraryDuration, after_timestamp - before_timestamp);
62 }
63 
64 struct WaitTask : public Task {
WaitTask__anon6cb087330111::WaitTask65   WaitTask(TimeFuture<SystemClock>&& future)
66       : future_(std::move(future)), completed_(false) {}
67 
DoPend__anon6cb087330111::WaitTask68   Poll<> DoPend(Context& cx) final {
69     if (future_.Pend(cx).IsPending()) {
70       return Pending();
71     }
72     completed_ = true;
73     return Ready();
74   }
75   TimeFuture<SystemClock> future_;
76   bool completed_;
77 };
78 
TEST(SimulatedTimeProvider,AdvanceTimeRunsPastTimers)79 TEST(SimulatedTimeProvider, AdvanceTimeRunsPastTimers) {
80   SimulatedTimeProvider<SystemClock> tp;
81   WaitTask task(tp.WaitFor(1h));
82   Dispatcher dispatcher;
83   dispatcher.Post(task);
84   tp.AdvanceTime(30min);
85   EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
86   tp.AdvanceTime(40min);
87   EXPECT_EQ(dispatcher.RunUntilStalled(), Ready());
88 }
89 
TEST(SimulatedTimeProvider,AdvanceUntilNextExpirationRunsPastTimers)90 TEST(SimulatedTimeProvider, AdvanceUntilNextExpirationRunsPastTimers) {
91   SimulatedTimeProvider<SystemClock> tp;
92   WaitTask task(tp.WaitFor(1h));
93   Dispatcher dispatcher;
94   dispatcher.Post(task);
95   EXPECT_TRUE(tp.AdvanceUntilNextExpiration());
96   EXPECT_EQ(dispatcher.RunUntilStalled(), Ready());
97   EXPECT_FALSE(tp.AdvanceUntilNextExpiration());
98 }
99 
TEST(SimulatedTimeProvider,TimeUntilNextExpirationGetsTimerDelay)100 TEST(SimulatedTimeProvider, TimeUntilNextExpirationGetsTimerDelay) {
101   SimulatedTimeProvider<SystemClock> tp;
102   auto timer = tp.WaitFor(1h);
103   ASSERT_TRUE(tp.TimeUntilNextExpiration().has_value());
104   EXPECT_GE(*tp.TimeUntilNextExpiration(), 1h);
105 }
106 
TEST(SimulatedTimeProvider,TimeUntilNextExpirationAfterCompletionReturnsNullopt)107 TEST(SimulatedTimeProvider,
108      TimeUntilNextExpirationAfterCompletionReturnsNullopt) {
109   SimulatedTimeProvider<SystemClock> tp;
110   auto timer = tp.WaitFor(1h);
111   tp.AdvanceTime(90min);
112   EXPECT_FALSE(tp.TimeUntilNextExpiration().has_value());
113 }
114 
TEST(SimulatedTimeProvider,TimeUntilNextExpirationAfterDestroyReturnsNullopt)115 TEST(SimulatedTimeProvider, TimeUntilNextExpirationAfterDestroyReturnsNullopt) {
116   SimulatedTimeProvider<SystemClock> tp;
117   {
118     auto timer = tp.WaitFor(1h);
119   }
120   EXPECT_FALSE(tp.TimeUntilNextExpiration().has_value());
121 }
122 
TEST(SimulatedTimeProvider,ResetSetsTimerBackToPendingAndFiresAgain)123 TEST(SimulatedTimeProvider, ResetSetsTimerBackToPendingAndFiresAgain) {
124   SimulatedTimeProvider<SystemClock> tp;
125   Dispatcher dispatcher;
126 
127   auto timer = tp.WaitFor(1h);
128   EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsPending());
129   tp.AdvanceTime(90min);
130   EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsReady());
131   timer.Reset(timer.expiration() + 40min);
132   EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsPending());
133   tp.AdvanceTime(90min);
134   EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsReady());
135 }
136 
TEST(SimulatedTimeProvider,TimerWithPastExpirationExpiresImmediately)137 TEST(SimulatedTimeProvider, TimerWithPastExpirationExpiresImmediately) {
138   SimulatedTimeProvider<SystemClock> tp;
139   auto start = tp.now();
140   tp.AdvanceTime(90min);
141   auto timer = tp.WaitUntil(start + 30min);
142   Dispatcher dispatcher;
143   EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsReady());
144 }
145 
TEST(SimulatedTimeProvider,MultipleMovedTimersExpireInOrder)146 TEST(SimulatedTimeProvider, MultipleMovedTimersExpireInOrder) {
147   SimulatedTimeProvider<SystemClock> tp;
148   // Insert out-of-order to check that they become sorted.
149   auto t3_init = tp.WaitFor(3h);
150   auto t1_init = tp.WaitFor(1h);
151   auto t2_init = tp.WaitFor(2h);
152   // Move out of order to check that sorting is preserved.
153   WaitTask t2(std::move(t2_init));
154   WaitTask t1(std::move(t1_init));
155   WaitTask t3(std::move(t3_init));
156 
157   Dispatcher dispatcher;
158   dispatcher.Post(t1);
159   dispatcher.Post(t2);
160   dispatcher.Post(t3);
161 
162   EXPECT_TRUE(dispatcher.RunUntilStalled().IsPending());
163   EXPECT_FALSE(t1.completed_);
164   EXPECT_FALSE(t2.completed_);
165   EXPECT_FALSE(t3.completed_);
166 
167   // t1 should expire first.
168   EXPECT_TRUE(tp.AdvanceUntilNextExpiration());
169   EXPECT_TRUE(dispatcher.RunUntilStalled().IsPending());
170   EXPECT_TRUE(t1.completed_);
171   EXPECT_FALSE(t2.completed_);
172   EXPECT_FALSE(t3.completed_);
173 
174   // Then t2.
175   EXPECT_TRUE(tp.AdvanceUntilNextExpiration());
176   EXPECT_TRUE(dispatcher.RunUntilStalled().IsPending());
177   EXPECT_TRUE(t1.completed_);
178   EXPECT_TRUE(t2.completed_);
179   EXPECT_FALSE(t3.completed_);
180 
181   // Then t3.
182   EXPECT_TRUE(tp.AdvanceUntilNextExpiration());
183   EXPECT_TRUE(dispatcher.RunUntilStalled().IsReady());
184   EXPECT_TRUE(t1.completed_);
185   EXPECT_TRUE(t2.completed_);
186   EXPECT_TRUE(t3.completed_);
187 }
188 
189 }  // namespace
190