xref: /aosp_15_r20/external/cronet/base/timer/wall_clock_timer_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/timer/wall_clock_timer.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/test/mock_callback.h"
11 #include "base/test/power_monitor_test.h"
12 #include "base/test/simple_test_clock.h"
13 #include "base/test/task_environment.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace base {
18 
19 class WallClockTimerTest : public ::testing::Test {
20  protected:
21   // Fast-forwards virtual time by |delta|. If |with_power| is true, both
22   // |clock_| and |task_environment_| time will be fast-forwarded. Otherwise,
23   // only |clock_| time will be changed to mimic the behavior when machine is
24   // suspended.
25   // Power event will be triggered if |with_power| is set to false.
FastForwardBy(base::TimeDelta delay,bool with_power=true)26   void FastForwardBy(base::TimeDelta delay, bool with_power = true) {
27     if (!with_power)
28       fake_power_monitor_source_.Suspend();
29 
30     clock_.Advance(delay);
31 
32     if (with_power) {
33       task_environment_.FastForwardBy(delay);
34     } else {
35       fake_power_monitor_source_.Resume();
36       task_environment_.RunUntilIdle();
37     }
38   }
39 
40   base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
41   base::test::SingleThreadTaskEnvironment task_environment_{
42       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
43   base::SimpleTestClock clock_;
44 };
45 
TEST_F(WallClockTimerTest,PowerResume)46 TEST_F(WallClockTimerTest, PowerResume) {
47   ::testing::StrictMock<base::MockOnceClosure> callback;
48   // Set up a WallClockTimer that will fire in one minute.
49   WallClockTimer wall_clock_timer(&clock_,
50                                   task_environment_.GetMockTickClock());
51   constexpr auto delay = base::Minutes(1);
52   const auto start_time = base::Time::Now();
53   const auto run_time = start_time + delay;
54   clock_.SetNow(start_time);
55   wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
56   EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
57 
58   // Pretend that time jumps forward 30 seconds while the machine is suspended.
59   constexpr auto past_time = base::Seconds(30);
60   FastForwardBy(past_time, /*with_power=*/false);
61   // Ensure that the timer has not yet fired.
62   ::testing::Mock::VerifyAndClearExpectations(&callback);
63   EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
64 
65   // Expect that the timer fires at the desired run time.
66   EXPECT_CALL(callback, Run());
67   // Both Time::Now() and |task_environment_| MockTickClock::Now()
68   // go forward by (|delay| - |past_time|):
69   FastForwardBy(delay - past_time);
70   ::testing::Mock::VerifyAndClearExpectations(&callback);
71   EXPECT_FALSE(wall_clock_timer.IsRunning());
72 }
73 
TEST_F(WallClockTimerTest,UseTimerTwiceInRow)74 TEST_F(WallClockTimerTest, UseTimerTwiceInRow) {
75   ::testing::StrictMock<base::MockOnceClosure> first_callback;
76   ::testing::StrictMock<base::MockOnceClosure> second_callback;
77   const auto start_time = base::Time::Now();
78   clock_.SetNow(start_time);
79 
80   // Set up a WallClockTimer that will invoke |first_callback| in one minute.
81   // Once it's done, it will invoke |second_callback| after the other minute.
82   WallClockTimer wall_clock_timer(&clock_,
83                                   task_environment_.GetMockTickClock());
84   constexpr auto delay = base::Minutes(1);
85   wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
86   EXPECT_CALL(first_callback, Run())
87       .WillOnce(::testing::InvokeWithoutArgs(
88           [this, &wall_clock_timer, &second_callback, delay]() {
89             wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
90                                    second_callback.Get());
91           }));
92 
93   FastForwardBy(delay);
94   ::testing::Mock::VerifyAndClearExpectations(&first_callback);
95   ::testing::Mock::VerifyAndClearExpectations(&second_callback);
96 
97   // When the |wall_clock_time| is used for the second time, it can still handle
98   // power suspension properly.
99   constexpr auto past_time = base::Seconds(30);
100   FastForwardBy(past_time, /*with_power=*/false);
101   ::testing::Mock::VerifyAndClearExpectations(&second_callback);
102 
103   EXPECT_CALL(second_callback, Run());
104   FastForwardBy(delay - past_time);
105   ::testing::Mock::VerifyAndClearExpectations(&second_callback);
106 }
107 
TEST_F(WallClockTimerTest,Stop)108 TEST_F(WallClockTimerTest, Stop) {
109   ::testing::StrictMock<base::MockOnceClosure> callback;
110   clock_.SetNow(base::Time::Now());
111 
112   // Set up a WallClockTimer.
113   WallClockTimer wall_clock_timer(&clock_,
114                                   task_environment_.GetMockTickClock());
115   constexpr auto delay = base::Minutes(1);
116   wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
117 
118   // After 20 seconds, timer is stopped.
119   constexpr auto past_time = base::Seconds(20);
120   FastForwardBy(past_time);
121   EXPECT_TRUE(wall_clock_timer.IsRunning());
122   wall_clock_timer.Stop();
123   EXPECT_FALSE(wall_clock_timer.IsRunning());
124 
125   // When power is suspends and resumed, timer won't be resumed.
126   FastForwardBy(past_time, /*with_power=*/false);
127   EXPECT_FALSE(wall_clock_timer.IsRunning());
128 
129   // Timer won't fire when desired run time is reached.
130   FastForwardBy(delay - past_time * 2);
131   ::testing::Mock::VerifyAndClearExpectations(&callback);
132 }
133 
TEST_F(WallClockTimerTest,RestartRunningTimer)134 TEST_F(WallClockTimerTest, RestartRunningTimer) {
135   ::testing::StrictMock<base::MockOnceClosure> first_callback;
136   ::testing::StrictMock<base::MockOnceClosure> second_callback;
137   constexpr auto delay = base::Minutes(1);
138 
139   // Set up a WallClockTimer that will invoke |first_callback| in one minute.
140   clock_.SetNow(base::Time::Now());
141   WallClockTimer wall_clock_timer(&clock_,
142                                   task_environment_.GetMockTickClock());
143   wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
144 
145   // After 30 seconds, replace the timer with |second_callback| with new one
146   // minute delay.
147   constexpr auto past_time = delay / 2;
148   FastForwardBy(past_time);
149   wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
150                          second_callback.Get());
151 
152   // |first_callback| is due but it won't be called because it's replaced.
153   FastForwardBy(past_time);
154   ::testing::Mock::VerifyAndClearExpectations(&first_callback);
155   ::testing::Mock::VerifyAndClearExpectations(&second_callback);
156 
157   // Timer invokes the |second_callback|.
158   EXPECT_CALL(second_callback, Run());
159   FastForwardBy(past_time);
160   ::testing::Mock::VerifyAndClearExpectations(&first_callback);
161   ::testing::Mock::VerifyAndClearExpectations(&second_callback);
162 }
163 
TEST_F(WallClockTimerTest,DoubleStop)164 TEST_F(WallClockTimerTest, DoubleStop) {
165   ::testing::StrictMock<base::MockOnceClosure> callback;
166   clock_.SetNow(base::Time::Now());
167 
168   // Set up a WallClockTimer.
169   WallClockTimer wall_clock_timer(&clock_,
170                                   task_environment_.GetMockTickClock());
171   constexpr auto delay = base::Minutes(1);
172   wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
173 
174   // After 15 seconds, timer is stopped.
175   constexpr auto past_time = delay / 4;
176   FastForwardBy(past_time);
177   EXPECT_TRUE(wall_clock_timer.IsRunning());
178   wall_clock_timer.Stop();
179   EXPECT_FALSE(wall_clock_timer.IsRunning());
180 
181   // And timer is stopped again later. The second stop should be a no-op.
182   FastForwardBy(past_time);
183   EXPECT_FALSE(wall_clock_timer.IsRunning());
184   wall_clock_timer.Stop();
185   EXPECT_FALSE(wall_clock_timer.IsRunning());
186 
187   // Timer won't fire after stop.
188   FastForwardBy(past_time, /*with_power=*/false);
189   FastForwardBy(delay - past_time * 3);
190   ::testing::Mock::VerifyAndClearExpectations(&callback);
191 }
192 
193 // On some platforms, TickClock will never freeze. WallClockTimer are still
194 // supported on those platforms.
TEST_F(WallClockTimerTest,NonStopTickClock)195 TEST_F(WallClockTimerTest, NonStopTickClock) {
196   ::testing::StrictMock<base::MockOnceClosure> callback;
197   // Set up a WallClockTimer that will fire in one minute.
198   WallClockTimer wall_clock_timer(&clock_,
199                                   task_environment_.GetMockTickClock());
200   constexpr auto delay = base::Minutes(1);
201   const auto start_time = base::Time::Now();
202   const auto run_time = start_time + delay;
203   clock_.SetNow(start_time);
204   wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
205   EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
206 
207   // Pretend that time jumps forward 30 seconds while the machine is suspended.
208   constexpr auto past_time = base::Seconds(30);
209 
210   // Fastword with both clocks even the power is suspended.
211   fake_power_monitor_source_.Suspend();
212   clock_.SetNow(clock_.Now() + past_time);
213   task_environment_.FastForwardBy(past_time);
214   fake_power_monitor_source_.Resume();
215 
216   // Ensure that the timer has not yet fired.
217   ::testing::Mock::VerifyAndClearExpectations(&callback);
218   EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
219 
220   // Expect that the timer fires at the desired run time.
221   EXPECT_CALL(callback, Run());
222   // Both Time::Now() and |task_environment_| MockTickClock::Now()
223   // go forward by (|delay| - |past_time|):
224   FastForwardBy(delay - past_time);
225   ::testing::Mock::VerifyAndClearExpectations(&callback);
226   EXPECT_FALSE(wall_clock_timer.IsRunning());
227 }
228 
TEST_F(WallClockTimerTest,NonStopTickClockWithLongPause)229 TEST_F(WallClockTimerTest, NonStopTickClockWithLongPause) {
230   ::testing::StrictMock<base::MockOnceClosure> callback;
231   // Set up a WallClockTimer that will fire in one minute.
232   WallClockTimer wall_clock_timer(&clock_,
233                                   task_environment_.GetMockTickClock());
234   constexpr auto delay = base::Minutes(1);
235   const auto start_time = base::Time::Now();
236   const auto run_time = start_time + delay;
237   clock_.SetNow(start_time);
238   wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
239   EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
240 
241   // Pretend that time jumps forward 60 seconds while the machine is suspended.
242   constexpr auto past_time = base::Seconds(60);
243 
244   // Fastword with both clocks even the power is suspended. Timer fires at the
245   // moment of power resume.
246   EXPECT_CALL(callback, Run());
247   fake_power_monitor_source_.Suspend();
248   clock_.SetNow(clock_.Now() + past_time);
249   task_environment_.FastForwardBy(past_time);
250   fake_power_monitor_source_.Resume();
251 
252   ::testing::Mock::VerifyAndClearExpectations(&callback);
253   EXPECT_FALSE(wall_clock_timer.IsRunning());
254 }
255 
256 }  // namespace base
257