123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/timer/wall_clock_timer.h"
- #include <memory>
- #include <utility>
- #include "base/test/mock_callback.h"
- #include "base/test/power_monitor_test.h"
- #include "base/test/simple_test_clock.h"
- #include "base/test/task_environment.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- class WallClockTimerTest : public ::testing::Test {
- protected:
- // Fast-forwards virtual time by |delta|. If |with_power| is true, both
- // |clock_| and |task_environment_| time will be fast-forwarded. Otherwise,
- // only |clock_| time will be changed to mimic the behavior when machine is
- // suspended.
- // Power event will be triggered if |with_power| is set to false.
- void FastForwardBy(base::TimeDelta delay, bool with_power = true) {
- if (!with_power)
- fake_power_monitor_source_.Suspend();
- clock_.Advance(delay);
- if (with_power) {
- task_environment_.FastForwardBy(delay);
- } else {
- fake_power_monitor_source_.Resume();
- task_environment_.RunUntilIdle();
- }
- }
- base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
- base::test::SingleThreadTaskEnvironment task_environment_{
- base::test::TaskEnvironment::TimeSource::MOCK_TIME};
- base::SimpleTestClock clock_;
- };
- TEST_F(WallClockTimerTest, PowerResume) {
- ::testing::StrictMock<base::MockOnceClosure> callback;
- // Set up a WallClockTimer that will fire in one minute.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- const auto start_time = base::Time::Now();
- const auto run_time = start_time + delay;
- clock_.SetNow(start_time);
- wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
- EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
- // Pretend that time jumps forward 30 seconds while the machine is suspended.
- constexpr auto past_time = base::Seconds(30);
- FastForwardBy(past_time, /*with_power=*/false);
- // Ensure that the timer has not yet fired.
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
- // Expect that the timer fires at the desired run time.
- EXPECT_CALL(callback, Run());
- // Both Time::Now() and |task_environment_| MockTickClock::Now()
- // go forward by (|delay| - |past_time|):
- FastForwardBy(delay - past_time);
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- }
- TEST_F(WallClockTimerTest, UseTimerTwiceInRow) {
- ::testing::StrictMock<base::MockOnceClosure> first_callback;
- ::testing::StrictMock<base::MockOnceClosure> second_callback;
- const auto start_time = base::Time::Now();
- clock_.SetNow(start_time);
- // Set up a WallClockTimer that will invoke |first_callback| in one minute.
- // Once it's done, it will invoke |second_callback| after the other minute.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
- EXPECT_CALL(first_callback, Run())
- .WillOnce(::testing::InvokeWithoutArgs(
- [this, &wall_clock_timer, &second_callback, delay]() {
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
- second_callback.Get());
- }));
- FastForwardBy(delay);
- ::testing::Mock::VerifyAndClearExpectations(&first_callback);
- ::testing::Mock::VerifyAndClearExpectations(&second_callback);
- // When the |wall_clock_time| is used for the second time, it can still handle
- // power suspension properly.
- constexpr auto past_time = base::Seconds(30);
- FastForwardBy(past_time, /*with_power=*/false);
- ::testing::Mock::VerifyAndClearExpectations(&second_callback);
- EXPECT_CALL(second_callback, Run());
- FastForwardBy(delay - past_time);
- ::testing::Mock::VerifyAndClearExpectations(&second_callback);
- }
- TEST_F(WallClockTimerTest, Stop) {
- ::testing::StrictMock<base::MockOnceClosure> callback;
- clock_.SetNow(base::Time::Now());
- // Set up a WallClockTimer.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
- // After 20 seconds, timer is stopped.
- constexpr auto past_time = base::Seconds(20);
- FastForwardBy(past_time);
- EXPECT_TRUE(wall_clock_timer.IsRunning());
- wall_clock_timer.Stop();
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- // When power is suspends and resumed, timer won't be resumed.
- FastForwardBy(past_time, /*with_power=*/false);
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- // Timer won't fire when desired run time is reached.
- FastForwardBy(delay - past_time * 2);
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- }
- TEST_F(WallClockTimerTest, RestartRunningTimer) {
- ::testing::StrictMock<base::MockOnceClosure> first_callback;
- ::testing::StrictMock<base::MockOnceClosure> second_callback;
- constexpr auto delay = base::Minutes(1);
- // Set up a WallClockTimer that will invoke |first_callback| in one minute.
- clock_.SetNow(base::Time::Now());
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
- // After 30 seconds, replace the timer with |second_callback| with new one
- // minute delay.
- constexpr auto past_time = delay / 2;
- FastForwardBy(past_time);
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
- second_callback.Get());
- // |first_callback| is due but it won't be called because it's replaced.
- FastForwardBy(past_time);
- ::testing::Mock::VerifyAndClearExpectations(&first_callback);
- ::testing::Mock::VerifyAndClearExpectations(&second_callback);
- // Timer invokes the |second_callback|.
- EXPECT_CALL(second_callback, Run());
- FastForwardBy(past_time);
- ::testing::Mock::VerifyAndClearExpectations(&first_callback);
- ::testing::Mock::VerifyAndClearExpectations(&second_callback);
- }
- TEST_F(WallClockTimerTest, DoubleStop) {
- ::testing::StrictMock<base::MockOnceClosure> callback;
- clock_.SetNow(base::Time::Now());
- // Set up a WallClockTimer.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
- // After 15 seconds, timer is stopped.
- constexpr auto past_time = delay / 4;
- FastForwardBy(past_time);
- EXPECT_TRUE(wall_clock_timer.IsRunning());
- wall_clock_timer.Stop();
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- // And timer is stopped again later. The second stop should be a no-op.
- FastForwardBy(past_time);
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- wall_clock_timer.Stop();
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- // Timer won't fire after stop.
- FastForwardBy(past_time, /*with_power=*/false);
- FastForwardBy(delay - past_time * 3);
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- }
- // On some platforms, TickClock will never freeze. WallClockTimer are still
- // supported on those platforms.
- TEST_F(WallClockTimerTest, NonStopTickClock) {
- ::testing::StrictMock<base::MockOnceClosure> callback;
- // Set up a WallClockTimer that will fire in one minute.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- const auto start_time = base::Time::Now();
- const auto run_time = start_time + delay;
- clock_.SetNow(start_time);
- wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
- EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
- // Pretend that time jumps forward 30 seconds while the machine is suspended.
- constexpr auto past_time = base::Seconds(30);
- // Fastword with both clocks even the power is suspended.
- fake_power_monitor_source_.Suspend();
- clock_.SetNow(clock_.Now() + past_time);
- task_environment_.FastForwardBy(past_time);
- fake_power_monitor_source_.Resume();
- // Ensure that the timer has not yet fired.
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
- // Expect that the timer fires at the desired run time.
- EXPECT_CALL(callback, Run());
- // Both Time::Now() and |task_environment_| MockTickClock::Now()
- // go forward by (|delay| - |past_time|):
- FastForwardBy(delay - past_time);
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- }
- TEST_F(WallClockTimerTest, NonStopTickClockWithLongPause) {
- ::testing::StrictMock<base::MockOnceClosure> callback;
- // Set up a WallClockTimer that will fire in one minute.
- WallClockTimer wall_clock_timer(&clock_,
- task_environment_.GetMockTickClock());
- constexpr auto delay = base::Minutes(1);
- const auto start_time = base::Time::Now();
- const auto run_time = start_time + delay;
- clock_.SetNow(start_time);
- wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
- EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
- // Pretend that time jumps forward 60 seconds while the machine is suspended.
- constexpr auto past_time = base::Seconds(60);
- // Fastword with both clocks even the power is suspended. Timer fires at the
- // moment of power resume.
- EXPECT_CALL(callback, Run());
- fake_power_monitor_source_.Suspend();
- clock_.SetNow(clock_.Now() + past_time);
- task_environment_.FastForwardBy(past_time);
- fake_power_monitor_source_.Resume();
- ::testing::Mock::VerifyAndClearExpectations(&callback);
- EXPECT_FALSE(wall_clock_timer.IsRunning());
- }
- } // namespace base
|