diff options
author | mithro <mithro@mithis.com> | 2014-09-09 18:03:36 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-10 01:18:39 +0000 |
commit | 0c0ac6a1616778e3852e3f8b3248688ca9d899b2 (patch) | |
tree | 0f79cee120a2dbaba414e6828ce555f14b0f0c7c /cc/test | |
parent | dc6bae3bdc5154b73600a1180c0a82859b271a3f (diff) | |
download | chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.zip chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.tar.gz chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.tar.bz2 |
New features include;
* Actually running the tasks in the ordered you asked!
* Allow running only pending tasks, all tasks until idle, to a given time or
for a given period.
* Allow stopping of running tasks on *any* arbitrary condition. No longer will
your tasks stop working when someone adds a new task or changes the task
order!
* Task runner intimately connected to time and controls Now().
Supports both automatic management and manual control.
This change makes it possible for the scheduler_unit tests to be 100%
deterministic. It also allows them to be more flexible and less brittle.
BUG=380889
Review URL: https://codereview.chromium.org/387493002
Cr-Commit-Position: refs/heads/master@{#294059}
Diffstat (limited to 'cc/test')
-rw-r--r-- | cc/test/begin_frame_args_test.cc | 16 | ||||
-rw-r--r-- | cc/test/begin_frame_args_test.h | 8 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner.cc | 322 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner.h | 126 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner_unittest.cc | 420 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.cc | 48 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.h | 74 | ||||
-rw-r--r-- | cc/test/test_now_source.cc | 125 | ||||
-rw-r--r-- | cc/test/test_now_source.h | 60 |
9 files changed, 1158 insertions, 41 deletions
diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc index 83051b2..137d5e1 100644 --- a/cc/test/begin_frame_args_test.cc +++ b/cc/test/begin_frame_args_test.cc @@ -36,6 +36,22 @@ BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() { BeginFrameArgs::DefaultInterval()); } +BeginFrameArgs CreateBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src) { + base::TimeTicks now = now_src->Now(); + return BeginFrameArgs::Create(now, + now + (BeginFrameArgs::DefaultInterval() / 2), + BeginFrameArgs::DefaultInterval()); +} + +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src) { + base::TimeTicks now = now_src->Now(); + return BeginFrameArgs::Create(now, + now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval()); +} + bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) { return (lhs.frame_time == rhs.frame_time) && (lhs.deadline == rhs.deadline) && (lhs.interval == rhs.interval); diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h index 0ab1daf..1c75c37 100644 --- a/cc/test/begin_frame_args_test.h +++ b/cc/test/begin_frame_args_test.h @@ -9,6 +9,7 @@ #include "base/time/time.h" #include "cc/output/begin_frame_args.h" +#include "cc/test/test_now_source.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -21,6 +22,13 @@ BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, int64 interval); BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(); +// Creates a BeginFrameArgs using the fake Now value stored on the +// OrderSimpleTaskRunner. +BeginFrameArgs CreateBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src); +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src); + // gtest helpers -- these *must* be in the same namespace as the types they // operate on. diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc index 188ffe7..9f7f789 100644 --- a/cc/test/ordered_simple_task_runner.cc +++ b/cc/test/ordered_simple_task_runner.cc @@ -4,38 +4,322 @@ #include "cc/test/ordered_simple_task_runner.h" -#include <algorithm> -#include <deque> +#include <limits> +#include <set> +#include <sstream> +#include <string> +#include <vector> -#include "base/logging.h" +#include "base/auto_reset.h" +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/string_number_conversions.h" -namespace { +#define TRACE_TASK(function, task) \ + TRACE_EVENT_INSTANT1( \ + "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); -bool TestPendingTaskComparator(const base::TestPendingTask& lhs, - const base::TestPendingTask& rhs) { - return lhs.ShouldRunBefore(rhs); +#define TRACE_TASK_RUN(function, tag, task) + +namespace cc { + +// TestOrderablePendingTask implementation +TestOrderablePendingTask::TestOrderablePendingTask() + : base::TestPendingTask(), + task_id_(TestOrderablePendingTask::task_id_counter++) { } +TestOrderablePendingTask::TestOrderablePendingTask( + const tracked_objects::Location& location, + const base::Closure& task, + base::TimeTicks post_time, + base::TimeDelta delay, + TestNestability nestability) + : base::TestPendingTask(location, task, post_time, delay, nestability), + task_id_(TestOrderablePendingTask::task_id_counter++) { } -namespace cc { +size_t TestOrderablePendingTask::task_id_counter = 0; + +TestOrderablePendingTask::~TestOrderablePendingTask() { +} + +bool TestOrderablePendingTask::operator==( + const TestOrderablePendingTask& other) const { + return task_id_ == other.task_id_; +} + +bool TestOrderablePendingTask::operator<( + const TestOrderablePendingTask& other) const { + if (*this == other) + return false; + + if (GetTimeToRun() == other.GetTimeToRun()) { + return task_id_ < other.task_id_; + } + return ShouldRunBefore(other); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +TestOrderablePendingTask::AsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} -OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} +void TestOrderablePendingTask::AsValueInto( + base::debug::TracedValue* state) const { + state->SetInteger("id", task_id_); + state->SetInteger("run_at", GetTimeToRun().ToInternalValue()); + state->SetString("posted_from", location.ToString()); +} + +OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() + : advance_now_(true), + now_src_(TestNowSource::Create(0)), + inside_run_tasks_until_(false) { +} + +OrderedSimpleTaskRunner::OrderedSimpleTaskRunner( + scoped_refptr<TestNowSource> now_src, + bool advance_now) + : advance_now_(advance_now), + now_src_(now_src), + max_tasks_(kAbsoluteMaxTasks), + inside_run_tasks_until_(false) { +} OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} -void OrderedSimpleTaskRunner::RunPendingTasks() { +// base::TestSimpleTaskRunner implementation +bool OrderedSimpleTaskRunner::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + DCHECK(thread_checker_.CalledOnValidThread()); + TestOrderablePendingTask pt( + from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE); + + TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); + pending_tasks_.insert(pt); + return true; +} + +bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + DCHECK(thread_checker_.CalledOnValidThread()); + TestOrderablePendingTask pt(from_here, + task, + now_src_->Now(), + delay, + base::TestPendingTask::NON_NESTABLE); + + TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt); + pending_tasks_.insert(pt); + return true; +} + +bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return true; +} + +base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { + if (pending_tasks_.size() <= 0) { + return TestNowSource::kAbsoluteMaxNow; + } + + return pending_tasks_.begin()->GetTimeToRun(); +} + +base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { DCHECK(thread_checker_.CalledOnValidThread()); - // Swap with a local variable to avoid re-entrancy problems. - std::deque<base::TestPendingTask> tasks_to_run; - tasks_to_run.swap(pending_tasks_); - std::stable_sort(tasks_to_run.begin(), - tasks_to_run.end(), - TestPendingTaskComparator); - for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); - it != tasks_to_run.end(); ++it) { - it->task.Run(); + + if (pending_tasks_.size() <= 0) { + return TestNowSource::kAbsoluteMaxNow - base::TimeTicks(); + } + + base::TimeDelta delay = NextTaskTime() - now_src_->Now(); + if (delay > base::TimeDelta()) + return delay; + return base::TimeDelta(); +} + +const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks = + std::numeric_limits<size_t>::max(); + +bool OrderedSimpleTaskRunner::RunTasksWhile( + base::Callback<bool(void)> condition) { + std::vector<base::Callback<bool(void)> > conditions(1); + conditions[0] = condition; + return RunTasksWhile(conditions); +} + +bool OrderedSimpleTaskRunner::RunTasksWhile( + const std::vector<base::Callback<bool(void)> >& conditions) { + TRACE_EVENT2("cc", + "OrderedSimpleTaskRunner::RunPendingTasks", + "this", + AsValue(), + "nested", + inside_run_tasks_until_); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (inside_run_tasks_until_) + return true; + + base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, + true); + + // Make a copy so we can append some extra run checks. + std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions); + + // Provide a timeout base on number of tasks run so this doesn't loop + // forever. + modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_)); + + // If to advance now or not + if (!advance_now_) { + modifiable_conditions.push_back(NowBefore(now_src_->Now())); + } else { + modifiable_conditions.push_back(AdvanceNow()); + } + + while (pending_tasks_.size() > 0) { + // Check if we should continue to run pending tasks. + bool condition_success = true; + for (std::vector<base::Callback<bool(void)> >::iterator it = + modifiable_conditions.begin(); + it != modifiable_conditions.end(); + it++) { + condition_success = it->Run(); + if (!condition_success) + break; + } + + // Conditions could modify the pending task length, so we need to recheck + // that there are tasks to run. + if (!condition_success || pending_tasks_.size() == 0) { + break; + } + + std::set<TestOrderablePendingTask>::iterator task_to_run = + pending_tasks_.begin(); + { + TRACE_EVENT1("cc", + "OrderedSimpleTaskRunner::RunPendingTasks running", + "task", + task_to_run->AsValue()); + task_to_run->task.Run(); + } + + pending_tasks_.erase(task_to_run); + } + + return pending_tasks_.size() > 0; +} + +bool OrderedSimpleTaskRunner::RunPendingTasks() { + return RunTasksWhile(TaskExistedInitially()); +} + +bool OrderedSimpleTaskRunner::RunUntilIdle() { + return RunTasksWhile(std::vector<base::Callback<bool(void)> >()); +} + +bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { + // If we are not auto advancing, force now forward to the time. + if (!advance_now_ && now_src_->Now() < time) + now_src_->SetNow(time); + + // Run tasks + bool result = RunTasksWhile(NowBefore(time)); + + // If the next task is after the stopping time and auto-advancing now, then + // force time to be the stopping time. + if (!result && advance_now_ && now_src_->Now() < time) { + now_src_->SetNow(time); + } + + return result; +} + +bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { + return RunUntilTime(now_src_->Now() + period); +} + +// base::debug tracing functionality +scoped_refptr<base::debug::ConvertableToTraceFormat> +OrderedSimpleTaskRunner::AsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} + +void OrderedSimpleTaskRunner::AsValueInto( + base::debug::TracedValue* state) const { + state->SetInteger("pending_tasks", pending_tasks_.size()); + for (std::set<TestOrderablePendingTask>::const_iterator it = + pending_tasks_.begin(); + it != pending_tasks_.end(); + ++it) { + state->BeginDictionary( + base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); + it->AsValueInto(state); + state->EndDictionary(); + } + now_src_->AsValueInto(state); +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( + size_t max_tasks) { + return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, + max_tasks, + base::Owned(new size_t(0))); +} + +bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, + size_t* tasks_run) { + return (*tasks_run)++ < max_tasks; +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() { + // base::Bind takes a copy of pending_tasks_ + return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback, + base::Unretained(this), + pending_tasks_); +} + +bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( + const std::set<TestOrderablePendingTask>& existing_tasks) { + return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( + base::TimeTicks stop_at) { + return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, + base::Unretained(this), + stop_at); +} +bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { + return NextTaskTime() <= stop_at; +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { + return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, + base::Unretained(this)); +} + +bool OrderedSimpleTaskRunner::AdvanceNowCallback() { + base::TimeTicks next_task_time = NextTaskTime(); + if (now_src_->Now() < next_task_time) { + now_src_->SetNow(next_task_time); } + return true; } } // namespace cc diff --git a/cc/test/ordered_simple_task_runner.h b/cc/test/ordered_simple_task_runner.h index 8850a76..61b5ab05 100644 --- a/cc/test/ordered_simple_task_runner.h +++ b/cc/test/ordered_simple_task_runner.h @@ -5,24 +5,146 @@ #ifndef CC_TEST_ORDERED_SIMPLE_TASK_RUNNER_H_ #define CC_TEST_ORDERED_SIMPLE_TASK_RUNNER_H_ +#include <limits> +#include <set> +#include <vector> + #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" #include "base/test/test_simple_task_runner.h" +#include "cc/test/test_now_source.h" namespace cc { +// Subclass of TestPendingTask which has a unique ID for every task, supports +// being used inside a std::set and has debug tracing support. +class TestOrderablePendingTask : public base::TestPendingTask { + public: + TestOrderablePendingTask(); + TestOrderablePendingTask(const tracked_objects::Location& location, + const base::Closure& task, + base::TimeTicks post_time, + base::TimeDelta delay, + TestNestability nestability); + ~TestOrderablePendingTask(); + + // operators needed by std::set and comparison + bool operator==(const TestOrderablePendingTask& other) const; + bool operator<(const TestOrderablePendingTask& other) const; + + // debug tracing functions + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + void AsValueInto(base::debug::TracedValue* state) const; + + private: + static size_t task_id_counter; + const size_t task_id_; +}; + // This runs pending tasks based on task's post_time + delay. // We should not execute a delayed task sooner than some of the queued tasks // which don't have a delay even though it is queued early. -class OrderedSimpleTaskRunner : public base::TestSimpleTaskRunner { +class OrderedSimpleTaskRunner : public base::SingleThreadTaskRunner { public: OrderedSimpleTaskRunner(); + OrderedSimpleTaskRunner(scoped_refptr<TestNowSource> now_src, + bool advance_now); + + // base::TestSimpleTaskRunner implementation: + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + + virtual bool RunsTasksOnCurrentThread() const OVERRIDE; + + // Set a maximum number of tasks to run at once. Useful as a timeout to + // prevent infinite task loops. + static const size_t kAbsoluteMaxTasks; + void SetRunTaskLimit(size_t max_tasks) { max_tasks_ = max_tasks; } + void ClearRunTaskLimit() { max_tasks_ = kAbsoluteMaxTasks; } + + // Allow task runner to advance now when running tasks. + void SetAutoAdvanceNowToPendingTasks(bool advance_now) { + advance_now_ = advance_now; + } + + base::TimeTicks NextTaskTime(); + base::TimeDelta DelayToNextTaskTime(); + + // Run tasks while the callback returns true or too many tasks have been run. + // Returns true if there are still pending tasks left. + bool RunTasksWhile(base::Callback<bool(void)> condition); - virtual void RunPendingTasks() OVERRIDE; + // Run tasks while *all* of the callbacks return true or too many tasks have + // been run. Exits on the *first* condition which returns false, skipping + // calling all remaining conditions. Conditions can have side effects, + // including modifying the task queue. + // Returns true if there are still pending tasks left. + bool RunTasksWhile( + const std::vector<base::Callback<bool(void)> >& conditions); + + // Convenience functions to run tasks with common conditions. + + // Run tasks which existed at the start of this call. + // Return code indicates tasks still exist to run. + bool RunPendingTasks(); + // Keep running tasks until no tasks are left. + // Return code indicates tasks still exist to run which also indicates if + // runner reached idle. + bool RunUntilIdle(); + // Keep running tasks until given time period. + // Return code indicates tasks still exist to run. + bool RunUntilTime(base::TimeTicks time); + bool RunForPeriod(base::TimeDelta period); + + // base::debug tracing functionality + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + virtual void AsValueInto(base::debug::TracedValue* state) const; + + // Common conditions to run for, exposed publicly to allow external users to + // use their own combinations. + // ------------------------------------------------------------------------- + + // Keep running until the given number of tasks have run. + // You generally shouldn't use this check as it will cause your tests to fail + // when code is changed adding a new task. It is useful as a "timeout" type + // solution. + base::Callback<bool(void)> TaskRunCountBelow(size_t max_tasks); + + // Keep running until a task which didn't exist initially would run. + base::Callback<bool(void)> TaskExistedInitially(); + + // Stop running tasks when NextTaskTime() >= stop_at + base::Callback<bool(void)> NowBefore(base::TimeTicks stop_at); + + // Advance Now() to the next task to run. + base::Callback<bool(void)> AdvanceNow(); protected: + static bool TaskRunCountBelowCallback(size_t max_tasks, size_t* task_run); + bool TaskExistedInitiallyCallback( + const std::set<TestOrderablePendingTask>& existing_tasks); + bool NowBeforeCallback(base::TimeTicks stop_at); + bool AdvanceNowCallback(); + virtual ~OrderedSimpleTaskRunner(); + base::ThreadChecker thread_checker_; + + bool advance_now_; + scoped_refptr<TestNowSource> now_src_; + + size_t max_tasks_; + + bool inside_run_tasks_until_; + std::set<TestOrderablePendingTask> pending_tasks_; + private: DISALLOW_COPY_AND_ASSIGN(OrderedSimpleTaskRunner); }; diff --git a/cc/test/ordered_simple_task_runner_unittest.cc b/cc/test/ordered_simple_task_runner_unittest.cc index 3fbfd3b..8cafa16 100644 --- a/cc/test/ordered_simple_task_runner_unittest.cc +++ b/cc/test/ordered_simple_task_runner_unittest.cc @@ -5,62 +5,442 @@ #include <string> #include "base/cancelable_callback.h" +#include "base/format_macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "base/test/test_pending_task.h" #include "cc/test/ordered_simple_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" +// We pass EXPECT_TRUE / EXPECT_FALSE macros rather than a boolean as on some +// compilers EXPECT_EQ(false, XXXX) fails to compile as gtest tries to convert +// the false value to null causing a -Werror=conversion-null error. +#define RUN_AND_CHECK_RESULT( \ + tasks_remain_expect_macro, run_func, expected_result) \ + tasks_remain_expect_macro(task_runner_->run_func); \ + EXPECT_EQ(expected_result, executed_tasks_); \ + executed_tasks_ = ""; + +namespace { + +bool ReturnTrue() { + return true; +} + +bool ReturnFalse() { + return false; +} +}; + namespace cc { +TEST(TestOrderablePendingTask, Ordering) { + TestOrderablePendingTask a; + TestOrderablePendingTask b; + TestOrderablePendingTask c; + + EXPECT_EQ(a, a); + EXPECT_EQ(b, b); + EXPECT_EQ(c, c); + EXPECT_LT(a, b); + EXPECT_LT(b, c); + EXPECT_LT(a, c); + + TestOrderablePendingTask a2 = a; + EXPECT_EQ(a, a2); + EXPECT_LT(a2, b); + EXPECT_LT(b, c); + EXPECT_LT(a2, c); +} + class OrderedSimpleTaskRunnerTest : public testing::Test { public: - OrderedSimpleTaskRunnerTest() { - task_runner_ = new OrderedSimpleTaskRunner; + OrderedSimpleTaskRunnerTest() + : now_src_(TestNowSource::Create(base::TimeTicks())) { + task_runner_ = new OrderedSimpleTaskRunner(now_src_, true); } virtual ~OrderedSimpleTaskRunnerTest() {} protected: - void CreateAndPostTask(int task_num, base::TimeDelta delay) { + std::string executed_tasks_; + scoped_refptr<TestNowSource> now_src_; + scoped_refptr<OrderedSimpleTaskRunner> task_runner_; + + void PostTask(int task_num, base::TimeDelta delay) { base::Closure test_task = base::Bind(&OrderedSimpleTaskRunnerTest::Task, base::Unretained(this), task_num); task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); } - void RunAndCheckResult(const std::string expected_result) { - task_runner_->RunPendingTasks(); - EXPECT_EQ(expected_result, executed_tasks_); + void PostTaskWhichPostsInstantTask(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsInstantTask, + base::Unretained(this), + task_num); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); } - private: - std::string executed_tasks_; - scoped_refptr<OrderedSimpleTaskRunner> task_runner_; + void PostTaskWhichPostsDelayedTask(int task_num, + base::TimeDelta delay1, + base::TimeDelta delay2) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsDelayedTask, + base::Unretained(this), + task_num, + delay2); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay1); + } + void PostTaskWhichCallsRun(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichCallsRun, + base::Unretained(this), + task_num); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); + } + + void PostTaskWhichPostsTaskAgain(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsAgain, + base::Unretained(this), + task_num, + delay); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); + } + + private: void Task(int task_num) { if (!executed_tasks_.empty()) executed_tasks_ += " "; - executed_tasks_ += base::StringPrintf("%d", task_num); + executed_tasks_ += + base::StringPrintf("%d(%" PRId64 "ms)", + task_num, + now_src_->Now().ToInternalValue() / + base::Time::kMicrosecondsPerMillisecond); + } + + void TaskWhichPostsInstantTask(int task_num) { + Task(task_num); + PostTask(-task_num, base::TimeDelta()); + } + + void TaskWhichPostsDelayedTask(int task_num, base::TimeDelta delay) { + Task(task_num); + PostTask(-task_num, delay); + } + + void TaskWhichCallsRun(int task_num) { + Task(task_num); + task_runner_->RunPendingTasks(); + } + + void TaskWhichPostsAgain(int task_num, base::TimeDelta delay) { + Task(task_num); + PostTaskWhichPostsTaskAgain(task_num, delay); } DISALLOW_COPY_AND_ASSIGN(OrderedSimpleTaskRunnerTest); }; -TEST_F(OrderedSimpleTaskRunnerTest, BasicOrderingTest) { - CreateAndPostTask(1, base::TimeDelta()); - CreateAndPostTask(2, base::TimeDelta()); - CreateAndPostTask(3, base::TimeDelta()); +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTest) { + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta()); + PostTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); + + PostTask(4, base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "4(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta()); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-1(0ms) -2(0ms) -3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingDelayedTasks) { + PostTaskWhichPostsDelayedTask( + 1, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichPostsDelayedTask( + 2, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichPostsDelayedTask( + 3, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-1(1ms) -2(1ms) -3(1ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingReordingDelayedTasks) { + PostTaskWhichPostsDelayedTask(1, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(20)); + PostTaskWhichPostsDelayedTask(2, + base::TimeDelta::FromMilliseconds(2), + base::TimeDelta::FromMilliseconds(5)); + PostTaskWhichPostsDelayedTask(3, + base::TimeDelta::FromMilliseconds(3), + base::TimeDelta::FromMilliseconds(5)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(1ms) 2(2ms) 3(3ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-2(7ms) -3(8ms) -1(21ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingReordingDelayedTasksOverlap) { + PostTaskWhichPostsDelayedTask(1, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(5)); + PostTaskWhichPostsDelayedTask(2, + base::TimeDelta::FromMilliseconds(5), + base::TimeDelta::FromMilliseconds(10)); + PostTaskWhichPostsDelayedTask(3, + base::TimeDelta::FromMilliseconds(10), + base::TimeDelta::FromMilliseconds(1)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(1ms) 2(5ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "-1(6ms) 3(10ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-3(11ms) -2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingAndRentrantTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichCallsRun(2, base::TimeDelta()); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-1(0ms) -3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingDelayedAndRentrantTasks) { + PostTaskWhichPostsDelayedTask( + 1, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichCallsRun(2, base::TimeDelta()); + PostTaskWhichPostsDelayedTask( + 3, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); - RunAndCheckResult("1 2 3"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-1(1ms) -3(1ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); } TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedTasks) { - CreateAndPostTask(1, base::TimeDelta()); - CreateAndPostTask(2, base::TimeDelta::FromMilliseconds(15)); - CreateAndPostTask(3, base::TimeDelta()); - CreateAndPostTask(4, base::TimeDelta::FromMilliseconds(8)); + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "1(0ms) 3(0ms) 4(8ms) 2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedPostingTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + PostTaskWhichPostsInstantTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunPendingTasks(), "-1(0ms) -3(0ms) 4(8ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "-4(8ms) 2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedTasksManualNow) { + task_runner_->SetAutoAdvanceNowToPendingTasks(false); + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), ""); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), + base::TimeDelta::FromMilliseconds(8)); + now_src_->SetNow(base::TimeTicks::FromInternalValue(5000)); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), + base::TimeDelta::FromMilliseconds(3)); + now_src_->SetNow(base::TimeTicks::FromInternalValue(25000)); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "4(25ms) 2(25ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilIdle) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), "1(0ms) -1(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeAutoNow) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + base::TimeTicks run_at = base::TimeTicks(); + + run_at += base::TimeDelta::FromMilliseconds(2); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_at), "1(0ms) -1(0ms) 2(2ms) -2(2ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), "3(3ms) -3(3ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), ""); + EXPECT_EQ(run_at, now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeManualNow) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetAutoAdvanceNowToPendingTasks(false); + + base::TimeTicks run_at = base::TimeTicks(); + + run_at += base::TimeDelta::FromMilliseconds(2); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_at), "1(2ms) 2(2ms) -1(2ms) -2(2ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), "3(3ms) -3(3ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), ""); + EXPECT_EQ(run_at, now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunForPeriod) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, + RunForPeriod(base::TimeDelta::FromMilliseconds(2)), + "1(0ms) -1(0ms) 2(2ms) -2(2ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(2), + now_src_->Now()); + + RUN_AND_CHECK_RESULT(EXPECT_FALSE, + RunForPeriod(base::TimeDelta::FromMilliseconds(1)), + "3(3ms) -3(3ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), + now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunForPeriod(base::TimeDelta::FromMilliseconds(1)), ""); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4), + now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunTasksWhileWithCallback) { + base::Callback<bool(void)> return_true = base::Bind(&ReturnTrue); + base::Callback<bool(void)> return_false = base::Bind(&ReturnFalse); + + PostTask(1, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunTasksWhile(return_false), ""); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunTasksWhile(return_true), "1(0ms)"); +} + +TEST_F(OrderedSimpleTaskRunnerTest, EmptyTaskList) { + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), ""); + + ASSERT_EQ(base::TimeTicks(), now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunUntilTime(base::TimeTicks::FromInternalValue(100)), ""); + EXPECT_EQ(base::TimeTicks::FromInternalValue(100), now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunForPeriod(base::TimeDelta::FromInternalValue(100)), ""); + EXPECT_EQ(base::TimeTicks::FromInternalValue(200), now_src_->Now()); + + base::Callback<bool(void)> return_true = base::Bind(&ReturnTrue); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunTasksWhile(return_true), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunPendingTasksTimeout) { + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta()); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta()); + PostTask(5, base::TimeDelta()); + PostTask(6, base::TimeDelta()); + + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + + task_runner_->SetRunTaskLimit(2); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "4(0ms) 5(0ms)"); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilIdleTimeout) { + PostTaskWhichPostsTaskAgain(1, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), "1(3ms) 1(6ms) 1(9ms)"); + + task_runner_->SetRunTaskLimit(2); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), "1(12ms) 1(15ms)"); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeout) { + base::TimeTicks run_to = base::TimeTicks() + base::TimeDelta::FromSeconds(1); + + PostTask(1, base::TimeDelta::FromMilliseconds(1)); + PostTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTask(3, base::TimeDelta::FromMilliseconds(3)); + PostTask(4, base::TimeDelta::FromMilliseconds(4)); + PostTask(5, base::TimeDelta::FromMilliseconds(5)); + + EXPECT_EQ(base::TimeTicks(), now_src_->Now()); + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_to), "1(1ms) 2(2ms) 3(3ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), + now_src_->Now()); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilTime(run_to), ""); - RunAndCheckResult("1 3 4 2"); + task_runner_->SetRunTaskLimit(100); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_to), "4(4ms) 5(5ms)"); + EXPECT_EQ(run_to, now_src_->Now()); } } // namespace cc diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc index 3b35a54..7001b59 100644 --- a/cc/test/scheduler_test_common.cc +++ b/cc/test/scheduler_test_common.cc @@ -4,6 +4,8 @@ #include "cc/test/scheduler_test_common.h" +#include <string> + #include "base/logging.h" namespace cc { @@ -14,4 +16,50 @@ void FakeTimeSourceClient::OnTimerTick() { base::TimeTicks FakeDelayBasedTimeSource::Now() const { return now_; } +TestDelayBasedTimeSource::TestDelayBasedTimeSource( + scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner) + : DelayBasedTimeSource(interval, task_runner), now_src_(now_src) { +} + +base::TimeTicks TestDelayBasedTimeSource::Now() const { + return now_src_->Now(); +} + +std::string TestDelayBasedTimeSource::TypeString() const { + return "TestDelayBasedTimeSource"; +} + +TestDelayBasedTimeSource::~TestDelayBasedTimeSource() { +} + +TestScheduler::TestScheduler( + scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner) + : Scheduler(client, + scheduler_settings, + layer_tree_host_id, + test_task_runner), + now_src_(now_src), + test_task_runner_(test_task_runner.get()) { + if (!settings_.begin_frame_scheduling_enabled) { + scoped_refptr<DelayBasedTimeSource> time_source = + TestDelayBasedTimeSource::Create( + now_src, VSyncInterval(), test_task_runner_); + synthetic_begin_frame_source_.reset( + new SyntheticBeginFrameSource(this, time_source)); + } +} + +base::TimeTicks TestScheduler::Now() const { + return now_src_->Now(); +} + +TestScheduler::~TestScheduler() { +} + } // namespace cc diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 596358a..a502336 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h @@ -5,10 +5,14 @@ #ifndef CC_TEST_SCHEDULER_TEST_COMMON_H_ #define CC_TEST_SCHEDULER_TEST_COMMON_H_ +#include <string> + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "cc/scheduler/delay_based_time_source.h" +#include "cc/scheduler/scheduler.h" +#include "cc/test/ordered_simple_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -46,6 +50,76 @@ class FakeDelayBasedTimeSource : public DelayBasedTimeSource { base::TimeTicks now_; }; +class TestDelayBasedTimeSource : public DelayBasedTimeSource { + public: + static scoped_refptr<TestDelayBasedTimeSource> Create( + scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner) { + return make_scoped_refptr( + new TestDelayBasedTimeSource(now_src, interval, task_runner)); + } + + protected: + TestDelayBasedTimeSource(scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner); + + // Overridden from DelayBasedTimeSource + virtual ~TestDelayBasedTimeSource(); + virtual base::TimeTicks Now() const OVERRIDE; + virtual std::string TypeString() const OVERRIDE; + + scoped_refptr<TestNowSource> now_src_; +}; + +class TestScheduler : public Scheduler { + public: + static scoped_ptr<TestScheduler> Create( + scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id) { + // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval() + now_src->AdvanceNow(base::TimeDelta::FromMilliseconds(100)); + + scoped_refptr<OrderedSimpleTaskRunner> test_task_runner = + new OrderedSimpleTaskRunner(now_src, true); + return make_scoped_ptr(new TestScheduler(now_src, + client, + scheduler_settings, + layer_tree_host_id, + test_task_runner)); + } + + // Extra test helper functionality + bool IsBeginRetroFrameArgsEmpty() const { + return begin_retro_frame_args_.empty(); + } + + bool IsSyntheticBeginFrameSourceActive() const { + return synthetic_begin_frame_source_->IsActive(); + } + + OrderedSimpleTaskRunner& task_runner() { return *test_task_runner_; } + + virtual ~TestScheduler(); + + protected: + // Overridden from Scheduler. + virtual base::TimeTicks Now() const OVERRIDE; + + private: + TestScheduler(scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner); + + scoped_refptr<TestNowSource> now_src_; + OrderedSimpleTaskRunner* test_task_runner_; +}; + } // namespace cc #endif // CC_TEST_SCHEDULER_TEST_COMMON_H_ diff --git a/cc/test/test_now_source.cc b/cc/test/test_now_source.cc new file mode 100644 index 0000000..2ffb36e --- /dev/null +++ b/cc/test/test_now_source.cc @@ -0,0 +1,125 @@ +// Copyright 2014 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 <limits> +#include <string> + +#include "cc/test/test_now_source.h" + +namespace cc { + +// TestNowSource::Constructors +scoped_refptr<TestNowSource> TestNowSource::Create() { + return make_scoped_refptr(new TestNowSource()); +} + +scoped_refptr<TestNowSource> TestNowSource::Create(base::TimeTicks initial) { + return make_scoped_refptr(new TestNowSource(initial)); +} + +scoped_refptr<TestNowSource> TestNowSource::Create(int64_t initial) { + return make_scoped_refptr(new TestNowSource(initial)); +} + +TestNowSource::TestNowSource() + : initial_(base::TimeTicks::FromInternalValue(10000)), now_() { + Reset(); +} + +TestNowSource::TestNowSource(base::TimeTicks initial) + : initial_(initial), now_() { + Reset(); +} + +TestNowSource::TestNowSource(int64_t initial) + : initial_(base::TimeTicks::FromInternalValue(initial)), now_() { + Reset(); +} + +TestNowSource::~TestNowSource() { +} + +// TestNowSource actual functionality +void TestNowSource::Reset() { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::Reset", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "initial", + initial_); + now_ = initial_; +} + +base::TimeTicks TestNowSource::Now() const { + return now_; +} + +void TestNowSource::SetNow(base::TimeTicks time) { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::SetNow", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "new", + time); + DCHECK(time >= now_); // Time should always go forward. + now_ = time; +} + +void TestNowSource::AdvanceNow(base::TimeDelta period) { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::AdvanceNow", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "by", + period.ToInternalValue()); + DCHECK(now_ != kAbsoluteMaxNow); + DCHECK(period >= base::TimeDelta()); // Time should always go forward. + now_ += period; +} + +const base::TimeTicks TestNowSource::kAbsoluteMaxNow = + base::TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::max()); + +// TestNowSource::Convenience functions +void TestNowSource::AdvanceNowMicroseconds(int64_t period_in_microseconds) { + AdvanceNow(base::TimeDelta::FromMicroseconds(period_in_microseconds)); +} +void TestNowSource::SetNowMicroseconds(int64_t time_in_microseconds) { + SetNow(base::TimeTicks::FromInternalValue(time_in_microseconds)); +} + +// TestNowSource::Tracing functions +void TestNowSource::AsValueInto(base::debug::TracedValue* state) const { + state->SetInteger("now_in_microseconds", now_.ToInternalValue()); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> TestNowSource::AsValue() + const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} + +// TestNowSource::Pretty printing functions +std::string TestNowSource::ToString() const { + std::string output("TestNowSource("); + AsValue()->AppendAsTraceFormat(&output); + output += ")"; + return output; +} + +::std::ostream& operator<<(::std::ostream& os, + const scoped_refptr<TestNowSource>& src) { + os << src->ToString(); + return os; +} +void PrintTo(const scoped_refptr<TestNowSource>& src, ::std::ostream* os) { + *os << src; +} + +} // namespace cc diff --git a/cc/test/test_now_source.h b/cc/test/test_now_source.h new file mode 100644 index 0000000..178a56b --- /dev/null +++ b/cc/test/test_now_source.h @@ -0,0 +1,60 @@ +// Copyright 2014 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. + +#ifndef CC_TEST_TEST_NOW_SOURCE_H_ +#define CC_TEST_TEST_NOW_SOURCE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/logging.h" + +namespace cc { + +class TestNowSource : public base::RefCounted<TestNowSource> { + public: + static scoped_refptr<TestNowSource> Create(); + static scoped_refptr<TestNowSource> Create(int64_t initial); + static scoped_refptr<TestNowSource> Create(base::TimeTicks initial); + + virtual void Reset(); + virtual base::TimeTicks Now() const; + virtual void SetNow(base::TimeTicks time); + virtual void AdvanceNow(base::TimeDelta period); + + // Convenience functions to make it the now source easier to use in unit + // tests. + void AdvanceNowMicroseconds(int64_t period_in_microseconds); + void SetNowMicroseconds(int64_t time_in_microseconds); + + static const base::TimeTicks kAbsoluteMaxNow; + + // Tracing functions + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + void AsValueInto(base::debug::TracedValue* state) const; + std::string ToString() const; + + protected: + TestNowSource(); + explicit TestNowSource(int64_t initial); + explicit TestNowSource(base::TimeTicks initial); + + base::TimeTicks initial_; + base::TimeTicks now_; + + private: + friend class base::RefCounted<TestNowSource>; + virtual ~TestNowSource(); +}; + +// gtest pretty printing functions +void PrintTo(const scoped_refptr<TestNowSource>& src, ::std::ostream* os); +::std::ostream& operator<<(::std::ostream& os, + const scoped_refptr<TestNowSource>& src); + +} // namespace cc + +#endif // CC_TEST_TEST_NOW_SOURCE_H_ |