summaryrefslogtreecommitdiffstats
path: root/cc/test
diff options
context:
space:
mode:
authormithro <mithro@mithis.com>2014-09-09 18:03:36 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-10 01:18:39 +0000
commit0c0ac6a1616778e3852e3f8b3248688ca9d899b2 (patch)
tree0f79cee120a2dbaba414e6828ce555f14b0f0c7c /cc/test
parentdc6bae3bdc5154b73600a1180c0a82859b271a3f (diff)
downloadchromium_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.cc16
-rw-r--r--cc/test/begin_frame_args_test.h8
-rw-r--r--cc/test/ordered_simple_task_runner.cc322
-rw-r--r--cc/test/ordered_simple_task_runner.h126
-rw-r--r--cc/test/ordered_simple_task_runner_unittest.cc420
-rw-r--r--cc/test/scheduler_test_common.cc48
-rw-r--r--cc/test/scheduler_test_common.h74
-rw-r--r--cc/test/test_now_source.cc125
-rw-r--r--cc/test/test_now_source.h60
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_