OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/renderer/scheduler/task_queue_manager.h" |
| 6 |
| 7 #include "base/test/test_simple_task_runner.h" |
| 8 #include "content/renderer/scheduler/task_queue_selector.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 |
| 11 namespace content { |
| 12 namespace { |
| 13 |
| 14 class SelectorForTest : public TaskQueueSelector { |
| 15 public: |
| 16 SelectorForTest() {} |
| 17 |
| 18 void RegisterWorkQueues( |
| 19 const std::vector<const base::TaskQueue*>& work_queues) override { |
| 20 work_queues_ = work_queues; |
| 21 } |
| 22 |
| 23 bool SelectWorkQueueToService(size_t* out_queue_index) override { |
| 24 if (queues_to_service_.empty()) |
| 25 return false; |
| 26 *out_queue_index = queues_to_service_.front(); |
| 27 queues_to_service_.pop_front(); |
| 28 return true; |
| 29 } |
| 30 |
| 31 void AppendQueueToService(size_t queue_index) { |
| 32 queues_to_service_.push_back(queue_index); |
| 33 } |
| 34 |
| 35 const std::vector<const base::TaskQueue*>& work_queues() { |
| 36 return work_queues_; |
| 37 } |
| 38 |
| 39 private: |
| 40 std::deque<size_t> queues_to_service_; |
| 41 std::vector<const base::TaskQueue*> work_queues_; |
| 42 |
| 43 DISALLOW_COPY_AND_ASSIGN(SelectorForTest); |
| 44 }; |
| 45 |
| 46 class TaskQueueManagerTest : public testing::Test { |
| 47 protected: |
| 48 void Initialize(size_t num_queues) { |
| 49 test_task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner()); |
| 50 selector_ = make_scoped_ptr(new SelectorForTest); |
| 51 manager_ = make_scoped_ptr( |
| 52 new TaskQueueManager(num_queues, test_task_runner_, selector_.get())); |
| 53 } |
| 54 |
| 55 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_; |
| 56 scoped_ptr<SelectorForTest> selector_; |
| 57 scoped_ptr<TaskQueueManager> manager_; |
| 58 }; |
| 59 |
| 60 void TestTask(int value, std::vector<int>* out_result) { |
| 61 out_result->push_back(value); |
| 62 } |
| 63 |
| 64 TEST_F(TaskQueueManagerTest, SingleQueuePosting) { |
| 65 Initialize(1u); |
| 66 EXPECT_EQ(1u, selector_->work_queues().size()); |
| 67 |
| 68 std::vector<int> run_order; |
| 69 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 70 manager_->TaskRunnerForQueue(0); |
| 71 |
| 72 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 73 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
| 74 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); |
| 75 |
| 76 selector_->AppendQueueToService(0); |
| 77 selector_->AppendQueueToService(0); |
| 78 selector_->AppendQueueToService(0); |
| 79 |
| 80 test_task_runner_->RunUntilIdle(); |
| 81 EXPECT_EQ(1, run_order[0]); |
| 82 EXPECT_EQ(2, run_order[1]); |
| 83 EXPECT_EQ(3, run_order[2]); |
| 84 } |
| 85 |
| 86 TEST_F(TaskQueueManagerTest, MultiQueuePosting) { |
| 87 Initialize(3u); |
| 88 EXPECT_EQ(3u, selector_->work_queues().size()); |
| 89 |
| 90 std::vector<int> run_order; |
| 91 scoped_refptr<base::SingleThreadTaskRunner> runners[3] = { |
| 92 manager_->TaskRunnerForQueue(0), |
| 93 manager_->TaskRunnerForQueue(1), |
| 94 manager_->TaskRunnerForQueue(2)}; |
| 95 |
| 96 selector_->AppendQueueToService(0); |
| 97 selector_->AppendQueueToService(1); |
| 98 selector_->AppendQueueToService(2); |
| 99 selector_->AppendQueueToService(0); |
| 100 selector_->AppendQueueToService(1); |
| 101 selector_->AppendQueueToService(2); |
| 102 |
| 103 runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 104 runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
| 105 runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); |
| 106 runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); |
| 107 runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order)); |
| 108 runners[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order)); |
| 109 |
| 110 test_task_runner_->RunUntilIdle(); |
| 111 EXPECT_EQ(1, run_order[0]); |
| 112 EXPECT_EQ(3, run_order[1]); |
| 113 EXPECT_EQ(5, run_order[2]); |
| 114 EXPECT_EQ(2, run_order[3]); |
| 115 EXPECT_EQ(4, run_order[4]); |
| 116 EXPECT_EQ(6, run_order[5]); |
| 117 } |
| 118 |
| 119 TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) { |
| 120 Initialize(1u); |
| 121 EXPECT_EQ(1u, selector_->work_queues().size()); |
| 122 |
| 123 std::vector<int> run_order; |
| 124 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 125 manager_->TaskRunnerForQueue(0); |
| 126 |
| 127 runner->PostNonNestableTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 128 |
| 129 // Non-nestable tasks never make it to the selector. |
| 130 test_task_runner_->RunUntilIdle(); |
| 131 EXPECT_EQ(1, run_order[0]); |
| 132 } |
| 133 |
| 134 TEST_F(TaskQueueManagerTest, QueuePolling) { |
| 135 Initialize(1u); |
| 136 |
| 137 std::vector<int> run_order; |
| 138 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 139 manager_->TaskRunnerForQueue(0); |
| 140 |
| 141 EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
| 142 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 143 EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
| 144 |
| 145 selector_->AppendQueueToService(0); |
| 146 test_task_runner_->RunUntilIdle(); |
| 147 EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
| 148 } |
| 149 |
| 150 TEST_F(TaskQueueManagerTest, DelayedTaskPosting) { |
| 151 Initialize(1u); |
| 152 |
| 153 std::vector<int> run_order; |
| 154 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 155 manager_->TaskRunnerForQueue(0); |
| 156 |
| 157 selector_->AppendQueueToService(0); |
| 158 |
| 159 base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); |
| 160 runner->PostDelayedTask( |
| 161 FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay); |
| 162 EXPECT_EQ(delay, test_task_runner_->NextPendingTaskDelay()); |
| 163 EXPECT_TRUE(manager_->IsQueueEmpty(0)); |
| 164 EXPECT_TRUE(run_order.empty()); |
| 165 |
| 166 // The task is inserted to the incoming queue only after the delay. |
| 167 test_task_runner_->RunPendingTasks(); |
| 168 EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
| 169 EXPECT_TRUE(run_order.empty()); |
| 170 |
| 171 // After the delay the task runs normally. |
| 172 selector_->AppendQueueToService(0); |
| 173 test_task_runner_->RunUntilIdle(); |
| 174 EXPECT_EQ(1, run_order[0]); |
| 175 } |
| 176 |
| 177 TEST_F(TaskQueueManagerTest, ManualPumping) { |
| 178 Initialize(1u); |
| 179 manager_->SetAutoPump(0, false); |
| 180 |
| 181 std::vector<int> run_order; |
| 182 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 183 manager_->TaskRunnerForQueue(0); |
| 184 |
| 185 // Posting a task when pumping is disabled doesn't result in work getting |
| 186 // posted. |
| 187 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 188 EXPECT_FALSE(test_task_runner_->HasPendingTask()); |
| 189 |
| 190 // However polling still works. |
| 191 EXPECT_FALSE(manager_->IsQueueEmpty(0)); |
| 192 |
| 193 // After pumping the task runs normally. |
| 194 manager_->PumpQueue(0); |
| 195 EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
| 196 selector_->AppendQueueToService(0); |
| 197 test_task_runner_->RunUntilIdle(); |
| 198 EXPECT_EQ(1, run_order[0]); |
| 199 } |
| 200 |
| 201 TEST_F(TaskQueueManagerTest, ManualPumpingToggle) { |
| 202 Initialize(1u); |
| 203 manager_->SetAutoPump(0, false); |
| 204 |
| 205 std::vector<int> run_order; |
| 206 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 207 manager_->TaskRunnerForQueue(0); |
| 208 |
| 209 // Posting a task when pumping is disabled doesn't result in work getting |
| 210 // posted. |
| 211 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 212 EXPECT_FALSE(test_task_runner_->HasPendingTask()); |
| 213 |
| 214 // When pumping is enabled the task runs normally. |
| 215 manager_->SetAutoPump(0, true); |
| 216 EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
| 217 selector_->AppendQueueToService(0); |
| 218 test_task_runner_->RunUntilIdle(); |
| 219 EXPECT_EQ(1, run_order[0]); |
| 220 } |
| 221 |
| 222 TEST_F(TaskQueueManagerTest, DenyRunning) { |
| 223 Initialize(1u); |
| 224 |
| 225 std::vector<int> run_order; |
| 226 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 227 manager_->TaskRunnerForQueue(0); |
| 228 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 229 |
| 230 // Since we haven't appended a work queue to be selected, the task doesn't |
| 231 // run. |
| 232 test_task_runner_->RunUntilIdle(); |
| 233 EXPECT_TRUE(run_order.empty()); |
| 234 |
| 235 // Pumping the queue again with a selected work queue runs the task. |
| 236 manager_->PumpQueue(0); |
| 237 selector_->AppendQueueToService(0); |
| 238 test_task_runner_->RunUntilIdle(); |
| 239 EXPECT_EQ(1, run_order[0]); |
| 240 } |
| 241 |
| 242 TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) { |
| 243 Initialize(1u); |
| 244 manager_->SetAutoPump(0, false); |
| 245 |
| 246 std::vector<int> run_order; |
| 247 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 248 manager_->TaskRunnerForQueue(0); |
| 249 |
| 250 // Posting a delayed task when pumping will apply the delay, but won't cause |
| 251 // work to executed afterwards. |
| 252 base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); |
| 253 runner->PostDelayedTask( |
| 254 FROM_HERE, base::Bind(&TestTask, 1, &run_order), delay); |
| 255 test_task_runner_->RunUntilIdle(); |
| 256 EXPECT_TRUE(run_order.empty()); |
| 257 |
| 258 // After pumping the task runs normally. |
| 259 manager_->PumpQueue(0); |
| 260 EXPECT_TRUE(test_task_runner_->HasPendingTask()); |
| 261 selector_->AppendQueueToService(0); |
| 262 test_task_runner_->RunUntilIdle(); |
| 263 EXPECT_EQ(1, run_order[0]); |
| 264 } |
| 265 |
| 266 TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) { |
| 267 Initialize(1u); |
| 268 manager_->SetAutoPump(0, false); |
| 269 |
| 270 std::vector<int> run_order; |
| 271 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 272 manager_->TaskRunnerForQueue(0); |
| 273 |
| 274 // Posting two tasks and pumping twice should result in two tasks in the work |
| 275 // queue. |
| 276 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 277 manager_->PumpQueue(0); |
| 278 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); |
| 279 manager_->PumpQueue(0); |
| 280 |
| 281 EXPECT_EQ(2u, selector_->work_queues()[0]->size()); |
| 282 } |
| 283 |
| 284 void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, |
| 285 int countdown, |
| 286 std::vector<int>* out_result) { |
| 287 out_result->push_back(countdown); |
| 288 if (--countdown) { |
| 289 runner->PostTask(FROM_HERE, |
| 290 Bind(&ReentrantTestTask, runner, countdown, out_result)); |
| 291 } |
| 292 } |
| 293 |
| 294 TEST_F(TaskQueueManagerTest, ReentrantPosting) { |
| 295 Initialize(1u); |
| 296 EXPECT_EQ(1u, selector_->work_queues().size()); |
| 297 |
| 298 std::vector<int> run_order; |
| 299 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 300 manager_->TaskRunnerForQueue(0); |
| 301 |
| 302 runner->PostTask(FROM_HERE, Bind(&ReentrantTestTask, runner, 3, &run_order)); |
| 303 |
| 304 selector_->AppendQueueToService(0); |
| 305 selector_->AppendQueueToService(0); |
| 306 selector_->AppendQueueToService(0); |
| 307 |
| 308 test_task_runner_->RunUntilIdle(); |
| 309 EXPECT_EQ(3, run_order[0]); |
| 310 EXPECT_EQ(2, run_order[1]); |
| 311 EXPECT_EQ(1, run_order[2]); |
| 312 } |
| 313 |
| 314 TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) { |
| 315 Initialize(1u); |
| 316 |
| 317 std::vector<int> run_order; |
| 318 scoped_refptr<base::SingleThreadTaskRunner> runner = |
| 319 manager_->TaskRunnerForQueue(0); |
| 320 |
| 321 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 322 manager_.reset(); |
| 323 selector_.reset(); |
| 324 runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); |
| 325 |
| 326 test_task_runner_->RunUntilIdle(); |
| 327 EXPECT_TRUE(run_order.empty()); |
| 328 } |
| 329 |
| 330 } // namespace |
| 331 } // namespace content |
OLD | NEW |