661 lines
21 KiB
C++
661 lines
21 KiB
C++
|
|
// Copyright 2012 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "base/timer/timer.h"
|
||
|
|
|
||
|
|
#include <stddef.h>
|
||
|
|
|
||
|
|
#include <memory>
|
||
|
|
|
||
|
|
#include "base/functional/bind.h"
|
||
|
|
#include "base/functional/callback.h"
|
||
|
|
#include "base/functional/callback_helpers.h"
|
||
|
|
#include "base/memory/ref_counted.h"
|
||
|
|
#include "base/run_loop.h"
|
||
|
|
#include "base/task/sequenced_task_runner.h"
|
||
|
|
#include "base/test/bind.h"
|
||
|
|
#include "base/test/mock_callback.h"
|
||
|
|
#include "base/test/task_environment.h"
|
||
|
|
#include "base/test/test_simple_task_runner.h"
|
||
|
|
#include "base/time/tick_clock.h"
|
||
|
|
#include "base/time/time.h"
|
||
|
|
#include "build/build_config.h"
|
||
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
|
||
|
|
namespace base {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
constexpr TimeDelta kTestDelay = Seconds(10);
|
||
|
|
constexpr TimeDelta kLongTestDelay = Minutes(10);
|
||
|
|
|
||
|
|
// The main thread types on which each timer should be tested.
|
||
|
|
const test::TaskEnvironment::MainThreadType testing_main_threads[] = {
|
||
|
|
test::TaskEnvironment::MainThreadType::DEFAULT,
|
||
|
|
test::TaskEnvironment::MainThreadType::IO,
|
||
|
|
#if !BUILDFLAG(IS_IOS) // iOS does not allow direct running of the UI loop.
|
||
|
|
test::TaskEnvironment::MainThreadType::UI,
|
||
|
|
#endif
|
||
|
|
};
|
||
|
|
|
||
|
|
class Receiver {
|
||
|
|
public:
|
||
|
|
Receiver() : count_(0) {}
|
||
|
|
void OnCalled() { count_++; }
|
||
|
|
bool WasCalled() { return count_ > 0; }
|
||
|
|
int TimesCalled() { return count_; }
|
||
|
|
|
||
|
|
private:
|
||
|
|
int count_;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Basic test with same setup as RunTest_OneShotTimers_Cancel below to confirm
|
||
|
|
// that |timer| would be fired in that test if it wasn't for the deletion.
|
||
|
|
void RunTest_OneShotTimers(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
OneShotTimer timer;
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_OneShotTimers_Cancel(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
auto timer = std::make_unique<OneShotTimer>();
|
||
|
|
auto* timer_ptr = timer.get();
|
||
|
|
|
||
|
|
// This should run before the timer expires.
|
||
|
|
SequencedTaskRunner::GetCurrentDefault()->DeleteSoon(FROM_HERE,
|
||
|
|
std::move(timer));
|
||
|
|
|
||
|
|
timer_ptr->Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_OneShotSelfDeletingTimer(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
auto timer = std::make_unique<OneShotTimer>();
|
||
|
|
auto* timer_ptr = timer.get();
|
||
|
|
|
||
|
|
timer_ptr->Start(
|
||
|
|
FROM_HERE, kTestDelay,
|
||
|
|
BindLambdaForTesting([&receiver, timer = std::move(timer)]() mutable {
|
||
|
|
receiver.OnCalled();
|
||
|
|
EXPECT_FALSE(timer->IsRunning());
|
||
|
|
timer.reset();
|
||
|
|
}));
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_RepeatingTimer(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type,
|
||
|
|
const TimeDelta& delay) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
RepeatingTimer timer;
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindRepeating(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(20 * kTestDelay);
|
||
|
|
EXPECT_EQ(receiver.TimesCalled(), 20);
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_RepeatingTimer_Cancel(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type,
|
||
|
|
const TimeDelta& delay) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
auto timer = std::make_unique<RepeatingTimer>();
|
||
|
|
auto* timer_ptr = timer.get();
|
||
|
|
|
||
|
|
// This should run before the timer expires.
|
||
|
|
SequencedTaskRunner::GetCurrentDefault()->DeleteSoon(FROM_HERE,
|
||
|
|
std::move(timer));
|
||
|
|
|
||
|
|
timer_ptr->Start(FROM_HERE, delay,
|
||
|
|
BindRepeating(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(delay);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_DelayTimer_NoCall(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled);
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_DelayTimer_OneCall(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled);
|
||
|
|
timer.Reset();
|
||
|
|
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_DelayTimer_Reset(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled);
|
||
|
|
timer.Reset();
|
||
|
|
|
||
|
|
// Fast-forward by a delay smaller than the timer delay. The timer will not
|
||
|
|
// fire.
|
||
|
|
task_environment.FastForwardBy(kTestDelay / 2);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
|
||
|
|
// Postpone the fire time.
|
||
|
|
timer.Reset();
|
||
|
|
|
||
|
|
// Verify that the timer does not fire at its original fire time.
|
||
|
|
task_environment.FastForwardBy(kTestDelay / 2);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
|
||
|
|
// Fast-forward by the timer delay. The timer will fire.
|
||
|
|
task_environment.FastForwardBy(kTestDelay / 2);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
void RunTest_DelayTimer_Deleted(
|
||
|
|
test::TaskEnvironment::MainThreadType main_thread_type) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
|
||
|
|
{
|
||
|
|
DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled);
|
||
|
|
timer.Reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Because the timer was deleted, it will never fire.
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Each test is run against each type of main thread. That way we are sure
|
||
|
|
// that timers work properly in all configurations.
|
||
|
|
|
||
|
|
class TimerTestWithThreadType
|
||
|
|
: public testing::TestWithParam<test::TaskEnvironment::MainThreadType> {};
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, OneShotTimers) {
|
||
|
|
RunTest_OneShotTimers(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, OneShotTimers_Cancel) {
|
||
|
|
RunTest_OneShotTimers_Cancel(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
// If underline timer does not handle properly, we will crash or fail
|
||
|
|
// in full page heap environment.
|
||
|
|
TEST_P(TimerTestWithThreadType, OneShotSelfDeletingTimer) {
|
||
|
|
RunTest_OneShotSelfDeletingTimer(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, OneShotTimer_CustomTaskRunner) {
|
||
|
|
auto task_runner = base::MakeRefCounted<TestSimpleTaskRunner>();
|
||
|
|
|
||
|
|
OneShotTimer timer;
|
||
|
|
|
||
|
|
bool task_ran = false;
|
||
|
|
|
||
|
|
// The timer will use the TestSimpleTaskRunner to schedule its delays.
|
||
|
|
timer.SetTaskRunner(task_runner);
|
||
|
|
timer.Start(FROM_HERE, Days(1),
|
||
|
|
BindLambdaForTesting([&]() { task_ran = true; }));
|
||
|
|
|
||
|
|
EXPECT_FALSE(task_ran);
|
||
|
|
EXPECT_TRUE(task_runner->HasPendingTask());
|
||
|
|
|
||
|
|
task_runner->RunPendingTasks();
|
||
|
|
|
||
|
|
EXPECT_TRUE(task_ran);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, OneShotTimerWithTickClock) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
Receiver receiver;
|
||
|
|
OneShotTimer timer(task_environment.GetMockTickClock());
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, RepeatingTimer) {
|
||
|
|
RunTest_RepeatingTimer(GetParam(), kTestDelay);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, RepeatingTimer_Cancel) {
|
||
|
|
RunTest_RepeatingTimer_Cancel(GetParam(), kTestDelay);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay) {
|
||
|
|
RunTest_RepeatingTimer(GetParam(), Seconds(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay_Cancel) {
|
||
|
|
RunTest_RepeatingTimer_Cancel(GetParam(), Seconds(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, RepeatingTimerWithTickClock) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
Receiver receiver;
|
||
|
|
const int expected_times_called = 10;
|
||
|
|
RepeatingTimer timer(task_environment.GetMockTickClock());
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindRepeating(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
task_environment.FastForwardBy(expected_times_called * kTestDelay);
|
||
|
|
timer.Stop();
|
||
|
|
EXPECT_EQ(expected_times_called, receiver.TimesCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, DelayTimer_NoCall) {
|
||
|
|
RunTest_DelayTimer_NoCall(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, DelayTimer_OneCall) {
|
||
|
|
RunTest_DelayTimer_OneCall(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, DelayTimer_Reset) {
|
||
|
|
RunTest_DelayTimer_Reset(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_P(TimerTestWithThreadType, DelayTimer_Deleted) {
|
||
|
|
RunTest_DelayTimer_Deleted(GetParam());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, DelayTimerWithTickClock) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
Receiver receiver;
|
||
|
|
DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled,
|
||
|
|
task_environment.GetMockTickClock());
|
||
|
|
task_environment.FastForwardBy(kTestDelay - Microseconds(1));
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
timer.Reset();
|
||
|
|
task_environment.FastForwardBy(kTestDelay - Microseconds(1));
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
timer.Reset();
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, TaskEnvironmentShutdown) {
|
||
|
|
// This test is designed to verify that shutdown of the
|
||
|
|
// message loop does not cause crashes if there were pending
|
||
|
|
// timers not yet fired. It may only trigger exceptions
|
||
|
|
// if debug heap checking is enabled.
|
||
|
|
Receiver receiver;
|
||
|
|
OneShotTimer timer;
|
||
|
|
|
||
|
|
{
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
} // Task environment destructs by falling out of scope.
|
||
|
|
|
||
|
|
EXPECT_FALSE(receiver.WasCalled());
|
||
|
|
// Timer destruct. SHOULD NOT CRASH, of course.
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, TaskEnvironmentSelfOwningTimer) {
|
||
|
|
// This test verifies that a timer does not cause crashes if
|
||
|
|
// |Timer::user_task_| owns the timer. The test may only trigger exceptions if
|
||
|
|
// debug heap checking is enabled.
|
||
|
|
|
||
|
|
auto timer = std::make_unique<OneShotTimer>();
|
||
|
|
auto* timer_ptr = timer.get();
|
||
|
|
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
|
||
|
|
timer_ptr->Start(FROM_HERE, kTestDelay,
|
||
|
|
BindLambdaForTesting([timer = std::move(timer)]() {}));
|
||
|
|
// |Timer::user_task_| owns sole reference to |timer|. Both will be destroyed
|
||
|
|
// once the task ran. SHOULD NOT CRASH.
|
||
|
|
task_environment.FastForwardUntilNoTasksRemain();
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, TaskEnvironmentSelfOwningTimerStopped) {
|
||
|
|
// This test verifies that a timer does not cause crashes when stopped if
|
||
|
|
// |Timer::user_task_| owns the timer. The test may only trigger exceptions if
|
||
|
|
// debug heap checking is enabled.
|
||
|
|
|
||
|
|
auto timer = std::make_unique<OneShotTimer>();
|
||
|
|
auto* timer_ptr = timer.get();
|
||
|
|
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
|
||
|
|
timer_ptr->Start(FROM_HERE, kTestDelay,
|
||
|
|
BindLambdaForTesting([timer = std::move(timer)]() {
|
||
|
|
// Stop destroys |Timer::user_task_| which owns sole
|
||
|
|
// reference to |timer|. SHOULD NOT CRASH.
|
||
|
|
timer->Stop();
|
||
|
|
}));
|
||
|
|
task_environment.FastForwardUntilNoTasksRemain();
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, NonRepeatIsRunning) {
|
||
|
|
{
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
OneShotTimer timer;
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Start(FROM_HERE, kTestDelay, DoNothing());
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
timer.Stop();
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
RetainingOneShotTimer timer;
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Start(FROM_HERE, kTestDelay, DoNothing());
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
timer.Stop();
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
ASSERT_FALSE(timer.user_task().is_null());
|
||
|
|
timer.Reset();
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, NonRepeatTaskEnvironmentDeath) {
|
||
|
|
OneShotTimer timer;
|
||
|
|
{
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Start(FROM_HERE, kTestDelay, DoNothing());
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, RetainRepeatIsRunning) {
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
RepeatingTimer timer(FROM_HERE, kTestDelay, DoNothing());
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Reset();
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
timer.Stop();
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Reset();
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, RetainNonRepeatIsRunning) {
|
||
|
|
test::TaskEnvironment task_environment;
|
||
|
|
RetainingOneShotTimer timer(FROM_HERE, kTestDelay, DoNothing());
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Reset();
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
timer.Stop();
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
timer.Reset();
|
||
|
|
EXPECT_TRUE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
TEST(TimerTest, ContinuationStopStart) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
|
||
|
|
Receiver receiver1;
|
||
|
|
Receiver receiver2;
|
||
|
|
OneShotTimer timer;
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver1)));
|
||
|
|
timer.Stop();
|
||
|
|
timer.Start(FROM_HERE, kLongTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver2)));
|
||
|
|
task_environment.FastForwardBy(kLongTestDelay);
|
||
|
|
EXPECT_FALSE(receiver1.WasCalled());
|
||
|
|
EXPECT_TRUE(receiver2.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, ContinuationReset) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
|
||
|
|
Receiver receiver;
|
||
|
|
OneShotTimer timer;
|
||
|
|
timer.Start(FROM_HERE, kTestDelay,
|
||
|
|
BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
|
||
|
|
timer.Reset();
|
||
|
|
// // Since Reset happened before task ran, the user_task must not be
|
||
|
|
// cleared: ASSERT_FALSE(timer.user_task().is_null());
|
||
|
|
task_environment.FastForwardBy(kTestDelay);
|
||
|
|
EXPECT_TRUE(receiver.WasCalled());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, AbandonedTaskIsCancelled) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
OneShotTimer timer;
|
||
|
|
|
||
|
|
// Start a timer. There will be a pending task on the current sequence.
|
||
|
|
timer.Start(FROM_HERE, kTestDelay, base::DoNothing());
|
||
|
|
EXPECT_EQ(1u, task_environment.GetPendingMainThreadTaskCount());
|
||
|
|
|
||
|
|
// After AbandonAndStop(), the task is correctly treated as cancelled.
|
||
|
|
timer.AbandonAndStop();
|
||
|
|
EXPECT_EQ(0u, task_environment.GetPendingMainThreadTaskCount());
|
||
|
|
EXPECT_FALSE(timer.IsRunning());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, DeadlineTimer) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
DeadlineTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
timer.Start(FROM_HERE, start + Seconds(5), run_loop.QuitClosure());
|
||
|
|
run_loop.Run();
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, DeadlineTimerCancel) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
DeadlineTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
MockRepeatingCallback<void()> callback;
|
||
|
|
timer.Start(FROM_HERE, start + Seconds(5), callback.Get());
|
||
|
|
|
||
|
|
EXPECT_CALL(callback, Run()).Times(0);
|
||
|
|
timer.Stop();
|
||
|
|
task_environment.FastForwardBy(Seconds(5));
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, DeadlineTimerTaskDestructed) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
DeadlineTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
MockRepeatingCallback<void()> destructed;
|
||
|
|
ScopedClosureRunner scoped_closure(destructed.Get());
|
||
|
|
timer.Start(FROM_HERE, start + Seconds(5),
|
||
|
|
BindOnce([](ScopedClosureRunner) {}, std::move(scoped_closure)));
|
||
|
|
|
||
|
|
EXPECT_CALL(destructed, Run());
|
||
|
|
timer.Stop();
|
||
|
|
testing::Mock::VerifyAndClearExpectations(&destructed);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, DeadlineTimerStartTwice) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
DeadlineTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
RunLoop run_loop;
|
||
|
|
timer.Start(FROM_HERE, start + Seconds(5), run_loop.QuitClosure());
|
||
|
|
timer.Start(FROM_HERE, start + Seconds(10), run_loop.QuitClosure());
|
||
|
|
run_loop.Run();
|
||
|
|
EXPECT_EQ(start + Seconds(10), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimer) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
MetronomeTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
// Ensure the run_loop.Run() below doesn't straddle over multiple ticks.
|
||
|
|
task_environment.AdvanceClock(
|
||
|
|
start.SnappedToNextTick(TimeTicks(), Seconds(5)) - start);
|
||
|
|
start = TimeTicks::Now();
|
||
|
|
|
||
|
|
RunLoop run_loop;
|
||
|
|
timer.Start(FROM_HERE, Seconds(5), run_loop.QuitClosure());
|
||
|
|
run_loop.Run();
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimerCustomPhase) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
MetronomeTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
timer.Start(FROM_HERE, Seconds(5), run_loop.QuitClosure(), start);
|
||
|
|
run_loop.Run();
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimerReset) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
MetronomeTimer timer(FROM_HERE, Seconds(5), run_loop.QuitClosure(), start);
|
||
|
|
|
||
|
|
timer.Reset();
|
||
|
|
run_loop.Run();
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimerStartTwice) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
MetronomeTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
{
|
||
|
|
RunLoop run_loop;
|
||
|
|
timer.Start(FROM_HERE, Seconds(4), run_loop.QuitClosure(), start);
|
||
|
|
run_loop.Run();
|
||
|
|
}
|
||
|
|
EXPECT_EQ(start + Seconds(4), TimeTicks::Now());
|
||
|
|
|
||
|
|
{
|
||
|
|
RunLoop run_loop;
|
||
|
|
timer.Start(FROM_HERE, Seconds(2), run_loop.QuitClosure(), start);
|
||
|
|
run_loop.Run();
|
||
|
|
}
|
||
|
|
EXPECT_EQ(start + Seconds(6), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimerMultiple) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
MetronomeTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
// Ensure the subsequent FastForwardBy() don't straddle over multiple ticks.
|
||
|
|
task_environment.AdvanceClock(
|
||
|
|
start.SnappedToNextTick(TimeTicks(), Seconds(5)) - start);
|
||
|
|
|
||
|
|
MockRepeatingCallback<void()> callback;
|
||
|
|
timer.Start(FROM_HERE, Seconds(5), callback.Get());
|
||
|
|
|
||
|
|
// The first tick is skipped because it is too close. Ticks at 5s and 10s.
|
||
|
|
EXPECT_CALL(callback, Run()).Times(2);
|
||
|
|
task_environment.FastForwardBy(Seconds(10));
|
||
|
|
|
||
|
|
EXPECT_CALL(callback, Run()).Times(2);
|
||
|
|
// Ticks at 15s and 25s, while 20s is missed.
|
||
|
|
task_environment.AdvanceClock(Seconds(12));
|
||
|
|
task_environment.FastForwardBy(Seconds(3));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TimerTest, MetronomeTimerCancel) {
|
||
|
|
test::TaskEnvironment task_environment(
|
||
|
|
test::TaskEnvironment::TimeSource::MOCK_TIME);
|
||
|
|
RunLoop run_loop;
|
||
|
|
MetronomeTimer timer;
|
||
|
|
TimeTicks start = TimeTicks::Now();
|
||
|
|
|
||
|
|
MockRepeatingCallback<void()> callback;
|
||
|
|
timer.Start(FROM_HERE, Seconds(5), callback.Get());
|
||
|
|
|
||
|
|
EXPECT_CALL(callback, Run()).Times(0);
|
||
|
|
timer.Stop();
|
||
|
|
task_environment.FastForwardBy(Seconds(5));
|
||
|
|
EXPECT_EQ(start + Seconds(5), TimeTicks::Now());
|
||
|
|
}
|
||
|
|
|
||
|
|
INSTANTIATE_TEST_SUITE_P(All,
|
||
|
|
TimerTestWithThreadType,
|
||
|
|
testing::ValuesIn(testing_main_threads));
|
||
|
|
|
||
|
|
} // namespace base
|