Index: content/renderer/scheduler/task_queue_manager_unittest.cc |
diff --git a/content/renderer/scheduler/task_queue_manager_unittest.cc b/content/renderer/scheduler/task_queue_manager_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0106eb23d52513d7a254cc310c86e273b7fb9789 |
--- /dev/null |
+++ b/content/renderer/scheduler/task_queue_manager_unittest.cc |
@@ -0,0 +1,331 @@ |
+// 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 "content/renderer/scheduler/task_queue_manager.h" |
+ |
+#include "base/test/test_simple_task_runner.h" |
+#include "content/renderer/scheduler/task_queue_selector.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+namespace { |
+ |
+class SelectorForTest : public TaskQueueSelector { |
+ public: |
+ SelectorForTest() {} |
+ |
+ void RegisterWorkQueues( |
+ const std::vector<const base::TaskQueue*>& work_queues) override { |
+ work_queues_ = work_queues; |
+ } |
+ |
+ bool SelectWorkQueueToService(size_t* out_queue_index) override { |
+ if (queues_to_service_.empty()) |
+ return false; |
+ *out_queue_index = queues_to_service_.front(); |
+ queues_to_service_.pop_front(); |
+ return true; |
+ } |
+ |
+ void AppendQueueToService(size_t queue_index) { |
+ queues_to_service_.push_back(queue_index); |
+ } |
+ |
+ const std::vector<const base::TaskQueue*>& work_queues() { |
+ return work_queues_; |
+ } |
+ |
+ private: |
+ std::deque<size_t> queues_to_service_; |
+ std::vector<const base::TaskQueue*> work_queues_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SelectorForTest); |
+}; |
+ |
+class TaskQueueManagerTest : public testing::Test { |
+ protected: |
+ void Initialize(size_t num_queues) { |
+ test_task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner()); |
+ selector_ = make_scoped_ptr(new SelectorForTest); |
+ manager_ = make_scoped_ptr( |
+ new TaskQueueManager(num_queues, test_task_runner_, selector_.get())); |
+ } |
+ |
+ scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_; |
+ scoped_ptr<SelectorForTest> selector_; |
+ scoped_ptr<TaskQueueManager> manager_; |
+}; |
+ |
+void TestTask(int value, std::vector<int>* out_result) { |
+ out_result->push_back(value); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, SingleQueuePosting) { |
+ Initialize(1u); |
+ EXPECT_EQ(1u, selector_->work_queues().size()); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); |
+ |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(0); |
+ |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+ EXPECT_EQ(2, run_order[1]); |
+ EXPECT_EQ(3, run_order[2]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, MultiQueuePosting) { |
+ Initialize(3u); |
+ EXPECT_EQ(3u, selector_->work_queues().size()); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runners[3] = { |
+ manager_->TaskRunnerForQueue(0), |
+ manager_->TaskRunnerForQueue(1), |
+ manager_->TaskRunnerForQueue(2)}; |
+ |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(1); |
+ selector_->AppendQueueToService(2); |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(1); |
+ selector_->AppendQueueToService(2); |
+ |
+ runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
+ runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); |
+ runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); |
+ runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order)); |
+ runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order)); |
+ |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+ EXPECT_EQ(3, run_order[1]); |
+ EXPECT_EQ(5, run_order[2]); |
+ EXPECT_EQ(2, run_order[3]); |
+ EXPECT_EQ(4, run_order[4]); |
+ EXPECT_EQ(6, run_order[5]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) { |
+ Initialize(1u); |
+ EXPECT_EQ(1u, selector_->work_queues().size()); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ runner->PostNonNestableTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ |
+ // Non-nestable tasks never make it to the selector. |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, QueuePolling) { |
+ Initialize(1u); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
+ |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, DelayedTaskPosting) { |
+ Initialize(1u); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ selector_->AppendQueueToService(0); |
+ |
+ base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); |
+ runner->PostDelayedTask( |
+ FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay); |
+ EXPECT_EQ(delay, test_task_runner_->NextPendingTaskDelay()); |
+ EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ // The task is inserted to the incoming queue only after the delay. |
+ test_task_runner_->RunPendingTasks(); |
+ EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ // After the delay the task runs normally. |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, ManualPumping) { |
+ Initialize(1u); |
+ manager_->SetAutoPump(0, false); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ // Posting a task when pumping is disabled doesn't result in work getting |
+ // posted. |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ EXPECT_FALSE(test_task_runner_->HasPendingTask()); |
+ |
+ // However polling still works. |
+ EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
+ |
+ // After pumping the task runs normally. |
+ manager_->PumpQueue(0); |
+ EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, ManualPumpingToggle) { |
+ Initialize(1u); |
+ manager_->SetAutoPump(0, false); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ // Posting a task when pumping is disabled doesn't result in work getting |
+ // posted. |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ EXPECT_FALSE(test_task_runner_->HasPendingTask()); |
+ |
+ // When pumping is enabled the task runs normally. |
+ manager_->SetAutoPump(0, true); |
+ EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, DenyRunning) { |
+ Initialize(1u); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ |
+ // Since we haven't appended a work queue to be selected, the task doesn't |
+ // run. |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ // Pumping the queue again with a selected work queue runs the task. |
+ manager_->PumpQueue(0); |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) { |
+ Initialize(1u); |
+ manager_->SetAutoPump(0, false); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ // Posting a delayed task when pumping will apply the delay, but won't cause |
+ // work to executed afterwards. |
+ base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); |
+ runner->PostDelayedTask( |
+ FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ // After pumping the task runs normally. |
+ manager_->PumpQueue(0); |
+ EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
+ selector_->AppendQueueToService(0); |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, run_order[0]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) { |
+ Initialize(1u); |
+ manager_->SetAutoPump(0, false); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ // Posting two tasks and pumping twice should result in two tasks in the work |
+ // queue. |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ manager_->PumpQueue(0); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
+ manager_->PumpQueue(0); |
+ |
+ EXPECT_EQ(2u, selector_->work_queues()[0]->size()); |
+} |
+ |
+void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, |
+ int countdown, |
+ std::vector<int>* out_result) { |
+ out_result->push_back(countdown); |
+ if (--countdown) { |
+ runner->PostTask(FROM_HERE, |
+ Bind(&ReentrantTestTask, runner, countdown, out_result)); |
+ } |
+} |
+ |
+TEST_F(TaskQueueManagerTest, ReentrantPosting) { |
+ Initialize(1u); |
+ EXPECT_EQ(1u, selector_->work_queues().size()); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ runner->PostTask(FROM_HERE, Bind(&ReentrantTestTask, runner, 3, &run_order)); |
+ |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(0); |
+ selector_->AppendQueueToService(0); |
+ |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(3, run_order[0]); |
+ EXPECT_EQ(2, run_order[1]); |
+ EXPECT_EQ(1, run_order[2]); |
+} |
+ |
+TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) { |
+ Initialize(1u); |
+ |
+ std::vector<int> run_order; |
+ scoped_refptr<base::SingleThreadTaskRunner> runner = |
+ manager_->TaskRunnerForQueue(0); |
+ |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ manager_.reset(); |
+ selector_.reset(); |
+ runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
+ |
+ test_task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(run_order.empty()); |
+} |
+ |
+} // namespace |
+} // namespace content |