diff options
author | engedy <engedy@chromium.org> | 2015-02-13 07:17:44 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-13 15:18:16 +0000 |
commit | 5cae03fa3f7f836be37d6dfb37cc8b3d7dcb3c3c (patch) | |
tree | f745c90e5a3c50c686c12c8b862073368ee6b0f8 /base/test | |
parent | ae130ef602aef780ed69597eb875dca2d904d473 (diff) | |
download | chromium_src-5cae03fa3f7f836be37d6dfb37cc8b3d7dcb3c3c.zip chromium_src-5cae03fa3f7f836be37d6dfb37cc8b3d7dcb3c3c.tar.gz chromium_src-5cae03fa3f7f836be37d6dfb37cc8b3d7dcb3c3c.tar.bz2 |
Add support in TestMockTimeTaskRunner for vending mock Time values and mock Clocks.
Previously, TestMockTimeTaskRunner had only supported vending out TimeTicks and TickClocks. Now it supports mock Time and mock Clocks too (they start at the Unix epoch).
This CL also shortens the names of the methods that vend the current time and time ticks to Now() and NowTicks(), respectively; removes using the "base" namespace prefix inside the "base" namespace; and provides a clean implementation for FastForwardUntilNoTasksRemain() instead of a hacky solution.
BUG=329911
TBR=phajdan.jr@chromium.org # OOO.
Review URL: https://codereview.chromium.org/899863002
Cr-Commit-Position: refs/heads/master@{#316219}
Diffstat (limited to 'base/test')
-rw-r--r-- | base/test/test_mock_time_task_runner.cc | 125 | ||||
-rw-r--r-- | base/test/test_mock_time_task_runner.h | 66 |
2 files changed, 135 insertions, 56 deletions
diff --git a/base/test/test_mock_time_task_runner.cc b/base/test/test_mock_time_task_runner.cc index 442d991..daba3bc 100644 --- a/base/test/test_mock_time_task_runner.cc +++ b/base/test/test_mock_time_task_runner.cc @@ -6,18 +6,21 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/time/clock.h" +#include "base/time/tick_clock.h" namespace base { namespace { -// TickClock that always returns the then-current mock time of |task_runner| as -// the current time. +// MockTickClock -------------------------------------------------------------- + +// TickClock that always returns the then-current mock time ticks of +// |task_runner| as the current time ticks. class MockTickClock : public TickClock { public: explicit MockTickClock( scoped_refptr<const TestMockTimeTaskRunner> task_runner); - ~MockTickClock() override; // TickClock: TimeTicks NowTicks() override; @@ -33,22 +36,47 @@ MockTickClock::MockTickClock( : task_runner_(task_runner) { } -MockTickClock::~MockTickClock() { +TimeTicks MockTickClock::NowTicks() { + return task_runner_->NowTicks(); } -TimeTicks MockTickClock::NowTicks() { - return task_runner_->GetCurrentMockTime(); +// MockClock ------------------------------------------------------------------ + +// Clock that always returns the then-current mock time of |task_runner| as the +// current time. +class MockClock : public Clock { + public: + explicit MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner); + + // Clock: + Time Now() override; + + private: + scoped_refptr<const TestMockTimeTaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(MockClock); +}; + +MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner) + : task_runner_(task_runner) { +} + +Time MockClock::Now() { + return task_runner_->Now(); } } // namespace +// TestMockTimeTaskRunner ----------------------------------------------------- + bool TestMockTimeTaskRunner::TemporalOrder::operator()( const TestPendingTask& first_task, const TestPendingTask& second_task) const { return first_task.GetTimeToRun() > second_task.GetTimeToRun(); } -TestMockTimeTaskRunner::TestMockTimeTaskRunner() { +TestMockTimeTaskRunner::TestMockTimeTaskRunner() + : now_(Time::UnixEpoch()) { } TestMockTimeTaskRunner::~TestMockTimeTaskRunner() { @@ -56,42 +84,38 @@ TestMockTimeTaskRunner::~TestMockTimeTaskRunner() { void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_GE(delta, TimeDelta()); - OnBeforeSelectingTask(); - - const base::TimeTicks original_now = now_; - TestPendingTask task_info; - while (DequeueNextTask(original_now, delta, &task_info)) { - if (task_info.GetTimeToRun() - now_ > base::TimeDelta()) { - now_ = task_info.GetTimeToRun(); - OnAfterTimePassed(); - } - - task_info.task.Run(); - - OnAfterTaskRun(); - OnBeforeSelectingTask(); - } - - if (!delta.is_max() && now_ - original_now < delta) { - now_ = original_now + delta; - OnAfterTimePassed(); - } + const TimeTicks original_now_ticks = now_ticks_; + ProcessAllTasksNoLaterThan(delta); + ForwardClocksUntilTickTime(original_now_ticks + delta); } void TestMockTimeTaskRunner::RunUntilIdle() { - FastForwardBy(TimeDelta()); + DCHECK(thread_checker_.CalledOnValidThread()); + ProcessAllTasksNoLaterThan(TimeDelta()); } void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() { - FastForwardBy(TimeDelta::Max()); + DCHECK(thread_checker_.CalledOnValidThread()); + ProcessAllTasksNoLaterThan(TimeDelta::Max()); } -TimeTicks TestMockTimeTaskRunner::GetCurrentMockTime() const { +Time TestMockTimeTaskRunner::Now() const { DCHECK(thread_checker_.CalledOnValidThread()); return now_; } +TimeTicks TestMockTimeTaskRunner::NowTicks() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return now_ticks_; +} + +scoped_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return make_scoped_ptr(new MockClock(this)); +} + scoped_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const { DCHECK(thread_checker_.CalledOnValidThread()); return make_scoped_ptr(new MockTickClock(this)); @@ -109,7 +133,8 @@ size_t TestMockTimeTaskRunner::GetPendingTaskCount() const { TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() const { DCHECK(thread_checker_.CalledOnValidThread()); - return tasks_.empty() ? TimeDelta::Max() : tasks_.top().GetTimeToRun() - now_; + return tasks_.empty() ? TimeDelta::Max() + : tasks_.top().GetTimeToRun() - now_ticks_; } bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const { @@ -120,9 +145,9 @@ bool TestMockTimeTaskRunner::PostDelayedTask( const tracked_objects::Location& from_here, const Closure& task, TimeDelta delay) { - base::AutoLock scoped_lock(tasks_lock_); - tasks_.push( - TestPendingTask(from_here, task, now_, delay, TestPendingTask::NESTABLE)); + AutoLock scoped_lock(tasks_lock_); + tasks_.push(TestPendingTask(from_here, task, now_ticks_, delay, + TestPendingTask::NESTABLE)); return true; } @@ -146,10 +171,36 @@ void TestMockTimeTaskRunner::OnAfterTaskRun() { // Empty default implementation. } -bool TestMockTimeTaskRunner::DequeueNextTask(const base::TimeTicks& reference, - const base::TimeDelta& max_delta, +void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) { + DCHECK_GE(max_delta, TimeDelta()); + const TimeTicks original_now_ticks = now_ticks_; + while (true) { + OnBeforeSelectingTask(); + TestPendingTask task_info; + if (!DequeueNextTask(original_now_ticks, max_delta, &task_info)) + break; + // If tasks were posted with a negative delay, task_info.GetTimeToRun() will + // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not + // moving the clock backwards in this case. + ForwardClocksUntilTickTime(task_info.GetTimeToRun()); + task_info.task.Run(); + OnAfterTaskRun(); + } +} + +void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) { + if (later_ticks <= now_ticks_) + return; + + now_ += later_ticks - now_ticks_; + now_ticks_ = later_ticks; + OnAfterTimePassed(); +} + +bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference, + const TimeDelta& max_delta, TestPendingTask* next_task) { - base::AutoLock scoped_lock(tasks_lock_); + AutoLock scoped_lock(tasks_lock_); if (!tasks_.empty() && (tasks_.top().GetTimeToRun() - reference) <= max_delta) { *next_task = tasks_.top(); diff --git a/base/test/test_mock_time_task_runner.h b/base/test/test_mock_time_task_runner.h index 2f59892..dbd80ae 100644 --- a/base/test/test_mock_time_task_runner.h +++ b/base/test/test_mock_time_task_runner.h @@ -14,11 +14,13 @@ #include "base/synchronization/lock.h" #include "base/test/test_pending_task.h" #include "base/threading/thread_checker.h" -#include "base/time/tick_clock.h" #include "base/time/time.h" namespace base { +class Clock; +class TickClock; + // Runs pending tasks in the order of the tasks' post time + delay, and keeps // track of a mock (virtual) tick clock time that can be fast-forwarded. // @@ -31,18 +33,26 @@ namespace base { // turn call back into it (e.g., to post more tasks). // - Tasks are stored in a priority queue, and executed in the increasing // order of post time + delay. +// - It does not check for overflow when doing time arithmetic``. A sufficient +// condition for preventing overflows is to make sure that the sum of all +// posted task delays and fast-forward increments is still representable by +// a TimeDelta, and that adding this delta to the starting values of Time +// and TickTime is still within their respective range. // - Non-nestable tasks are not supported. // - Tasks aren't guaranteed to be destroyed immediately after they're run. // // This is a slightly more sophisticated version of TestSimpleTaskRunner, in // that it supports running delayed tasks in the correct temporal order. -class TestMockTimeTaskRunner : public base::SingleThreadTaskRunner { +class TestMockTimeTaskRunner : public SingleThreadTaskRunner { public: + // Constructs an instance whose virtual time will start at the Unix epoch, and + // whose time ticks will start at zero. TestMockTimeTaskRunner(); // Fast-forwards virtual time by |delta|, causing all tasks with a remaining - // delay less than or equal to |delta| to be executed. - void FastForwardBy(base::TimeDelta delta); + // delay less than or equal to |delta| to be executed. |delta| must be + // non-negative. + void FastForwardBy(TimeDelta delta); // Fast-forwards virtual time just until all tasks are executed. void FastForwardUntilNoTasksRemain(); @@ -52,11 +62,18 @@ class TestMockTimeTaskRunner : public base::SingleThreadTaskRunner { // elapse. void RunUntilIdle(); - // Returns the current virtual time. - TimeTicks GetCurrentMockTime() const; + // Returns the current virtual time (initially starting at the Unix epoch). + Time Now() const; + + // Returns the current virtual tick time (initially starting at 0). + TimeTicks NowTicks() const; + + // Returns a Clock that uses the virtual time of |this| as its time source. + // The returned Clock will hold a reference to |this|. + scoped_ptr<Clock> GetMockClock() const; - // Returns a TickClock that uses the mock time of |this| as its time source. - // The returned TickClock will hold a reference to |this|. + // Returns a TickClock that uses the virtual time ticks of |this| as its tick + // source. The returned TickClock will hold a reference to |this|. scoped_ptr<TickClock> GetMockTickClock() const; bool HasPendingTask() const; @@ -66,12 +83,11 @@ class TestMockTimeTaskRunner : public base::SingleThreadTaskRunner { // SingleThreadTaskRunner: bool RunsTasksOnCurrentThread() const override; bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - TimeDelta delay) override; - bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - TimeDelta delay) override; + const Closure& task, + TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) override; protected: ~TestMockTimeTaskRunner() override; @@ -100,20 +116,32 @@ class TestMockTimeTaskRunner : public base::SingleThreadTaskRunner { std::vector<TestPendingTask>, TemporalOrder> TaskPriorityQueue; + // Core of the implementation for all flavors of fast-forward methods. Given a + // non-negative |max_delta|, runs all tasks with a remaining delay less than + // or equal to |max_delta|, and moves virtual time forward as needed for each + // processed task. Pass in TimeDelta::Max() as |max_delta| to run all tasks. + void ProcessAllTasksNoLaterThan(TimeDelta max_delta); + + // Forwards |now_ticks_| until it equals |later_ticks|, and forwards |now_| by + // the same amount. Calls OnAfterTimePassed() if |later_ticks| > |now_ticks_|. + // Does nothing if |later_ticks| <= |now_ticks_|. + void ForwardClocksUntilTickTime(TimeTicks later_ticks); + // Returns the |next_task| to run if there is any with a running time that is // at most |reference| + |max_delta|. This additional complexity is required // so that |max_delta| == TimeDelta::Max() can be supported. - bool DequeueNextTask(const base::TimeTicks& reference, - const base::TimeDelta& max_delta, + bool DequeueNextTask(const TimeTicks& reference, + const TimeDelta& max_delta, TestPendingTask* next_task); - base::ThreadChecker thread_checker_; - base::TimeTicks now_; + ThreadChecker thread_checker_; + Time now_; + TimeTicks now_ticks_; // Temporally ordered heap of pending tasks. Must only be accessed while the // |tasks_lock_| is held. TaskPriorityQueue tasks_; - base::Lock tasks_lock_; + Lock tasks_lock_; DISALLOW_COPY_AND_ASSIGN(TestMockTimeTaskRunner); }; |