wall_clock_timer_unittest.cc 10.0 KB

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