| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "components/scheduler/base/task_queue_selector.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <memory> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/ptr_util.h" | |
| 14 #include "base/pending_task.h" | |
| 15 #include "components/scheduler/base/task_queue_impl.h" | |
| 16 #include "components/scheduler/base/virtual_time_domain.h" | |
| 17 #include "components/scheduler/base/work_queue.h" | |
| 18 #include "components/scheduler/base/work_queue_sets.h" | |
| 19 #include "testing/gmock/include/gmock/gmock.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 | |
| 22 using testing::_; | |
| 23 | |
| 24 namespace scheduler { | |
| 25 namespace internal { | |
| 26 | |
| 27 class MockObserver : public TaskQueueSelector::Observer { | |
| 28 public: | |
| 29 MockObserver() {} | |
| 30 virtual ~MockObserver() {} | |
| 31 | |
| 32 MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*)); | |
| 33 MOCK_METHOD1(OnTriedToSelectBlockedWorkQueue, void(internal::WorkQueue*)); | |
| 34 | |
| 35 private: | |
| 36 DISALLOW_COPY_AND_ASSIGN(MockObserver); | |
| 37 }; | |
| 38 | |
| 39 class TaskQueueSelectorForTest : public TaskQueueSelector { | |
| 40 public: | |
| 41 using TaskQueueSelector::SetImmediateStarvationCountForTest; | |
| 42 using TaskQueueSelector::PrioritizingSelector; | |
| 43 using TaskQueueSelector::enabled_selector_for_test; | |
| 44 }; | |
| 45 | |
| 46 class TaskQueueSelectorTest : public testing::Test { | |
| 47 public: | |
| 48 TaskQueueSelectorTest() | |
| 49 : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {} | |
| 50 ~TaskQueueSelectorTest() override {} | |
| 51 | |
| 52 TaskQueueSelectorForTest::PrioritizingSelector* enabled_selector() { | |
| 53 return selector_.enabled_selector_for_test(); | |
| 54 } | |
| 55 | |
| 56 WorkQueueSets* delayed_work_queue_sets() { | |
| 57 return enabled_selector()->delayed_work_queue_sets(); | |
| 58 } | |
| 59 WorkQueueSets* immediate_work_queue_sets() { | |
| 60 return enabled_selector()->immediate_work_queue_sets(); | |
| 61 } | |
| 62 | |
| 63 void PushTasks(const size_t queue_indices[], size_t num_tasks) { | |
| 64 std::set<size_t> changed_queue_set; | |
| 65 for (size_t i = 0; i < num_tasks; i++) { | |
| 66 changed_queue_set.insert(queue_indices[i]); | |
| 67 task_queues_[queue_indices[i]]->immediate_work_queue()->Push( | |
| 68 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, | |
| 69 true, i)); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 void PushTasksWithEnqueueOrder(const size_t queue_indices[], | |
| 74 const size_t enqueue_orders[], | |
| 75 size_t num_tasks) { | |
| 76 std::set<size_t> changed_queue_set; | |
| 77 for (size_t i = 0; i < num_tasks; i++) { | |
| 78 changed_queue_set.insert(queue_indices[i]); | |
| 79 task_queues_[queue_indices[i]]->immediate_work_queue()->Push( | |
| 80 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, | |
| 81 true, enqueue_orders[i])); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 std::vector<size_t> PopTasks() { | |
| 86 std::vector<size_t> order; | |
| 87 WorkQueue* chosen_work_queue; | |
| 88 while (selector_.SelectWorkQueueToService(&chosen_work_queue)) { | |
| 89 size_t chosen_queue_index = | |
| 90 queue_to_index_map_.find(chosen_work_queue->task_queue())->second; | |
| 91 order.push_back(chosen_queue_index); | |
| 92 chosen_work_queue->PopTaskForTest(); | |
| 93 immediate_work_queue_sets()->OnPopQueue(chosen_work_queue); | |
| 94 } | |
| 95 return order; | |
| 96 } | |
| 97 | |
| 98 static void TestFunction() {} | |
| 99 | |
| 100 void EnableQueue(TaskQueueImpl* queue) { | |
| 101 queue->SetQueueEnabled(true); | |
| 102 selector_.EnableQueue(queue); | |
| 103 } | |
| 104 | |
| 105 void DisableQueue(TaskQueueImpl* queue) { | |
| 106 queue->SetQueueEnabled(false); | |
| 107 selector_.DisableQueue(queue); | |
| 108 } | |
| 109 | |
| 110 protected: | |
| 111 void SetUp() final { | |
| 112 virtual_time_domain_ = base::WrapUnique<VirtualTimeDomain>( | |
| 113 new VirtualTimeDomain(nullptr, base::TimeTicks())); | |
| 114 for (size_t i = 0; i < kTaskQueueCount; i++) { | |
| 115 scoped_refptr<TaskQueueImpl> task_queue = make_scoped_refptr( | |
| 116 new TaskQueueImpl(nullptr, virtual_time_domain_.get(), | |
| 117 TaskQueue::Spec("test queue"), "test", "test")); | |
| 118 selector_.AddQueue(task_queue.get()); | |
| 119 task_queues_.push_back(task_queue); | |
| 120 } | |
| 121 for (size_t i = 0; i < kTaskQueueCount; i++) { | |
| 122 EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[i]->GetQueuePriority()) | |
| 123 << i; | |
| 124 queue_to_index_map_.insert(std::make_pair(task_queues_[i].get(), i)); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void TearDown() final { | |
| 129 for (scoped_refptr<TaskQueueImpl>& task_queue : task_queues_) { | |
| 130 task_queue->UnregisterTaskQueue(); | |
| 131 // Note since this test doesn't have a TaskQueueManager we need to | |
| 132 // manually remove |task_queue| from the |selector_|. Normally | |
| 133 // UnregisterTaskQueue would do that. | |
| 134 selector_.RemoveQueue(task_queue.get()); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 scoped_refptr<TaskQueueImpl> NewTaskQueueWithBlockReporting() { | |
| 139 return make_scoped_refptr(new TaskQueueImpl( | |
| 140 nullptr, virtual_time_domain_.get(), | |
| 141 TaskQueue::Spec("test queue").SetShouldReportWhenExecutionBlocked(true), | |
| 142 "test", "test")); | |
| 143 } | |
| 144 | |
| 145 const size_t kTaskQueueCount = 5; | |
| 146 base::Closure test_closure_; | |
| 147 TaskQueueSelectorForTest selector_; | |
| 148 std::unique_ptr<VirtualTimeDomain> virtual_time_domain_; | |
| 149 std::vector<scoped_refptr<TaskQueueImpl>> task_queues_; | |
| 150 std::map<TaskQueueImpl*, size_t> queue_to_index_map_; | |
| 151 }; | |
| 152 | |
| 153 TEST_F(TaskQueueSelectorTest, TestDefaultPriority) { | |
| 154 size_t queue_order[] = {4, 3, 2, 1, 0}; | |
| 155 PushTasks(queue_order, 5); | |
| 156 EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0)); | |
| 157 } | |
| 158 | |
| 159 TEST_F(TaskQueueSelectorTest, TestHighPriority) { | |
| 160 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 161 PushTasks(queue_order, 5); | |
| 162 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 163 EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); | |
| 164 } | |
| 165 | |
| 166 TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) { | |
| 167 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 168 PushTasks(queue_order, 5); | |
| 169 selector_.SetQueuePriority(task_queues_[0].get(), | |
| 170 TaskQueue::BEST_EFFORT_PRIORITY); | |
| 171 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 172 EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 1, 3, 4, 0)); | |
| 173 } | |
| 174 | |
| 175 TEST_F(TaskQueueSelectorTest, TestControlPriority) { | |
| 176 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 177 PushTasks(queue_order, 5); | |
| 178 selector_.SetQueuePriority(task_queues_[4].get(), | |
| 179 TaskQueue::CONTROL_PRIORITY); | |
| 180 EXPECT_EQ(TaskQueue::CONTROL_PRIORITY, task_queues_[4]->GetQueuePriority()); | |
| 181 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 182 EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); | |
| 183 EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3)); | |
| 184 } | |
| 185 | |
| 186 TEST_F(TaskQueueSelectorTest, TestObserverWithEnabledQueue) { | |
| 187 DisableQueue(task_queues_[1].get()); | |
| 188 MockObserver mock_observer; | |
| 189 selector_.SetTaskQueueSelectorObserver(&mock_observer); | |
| 190 EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1); | |
| 191 EnableQueue(task_queues_[1].get()); | |
| 192 } | |
| 193 | |
| 194 TEST_F(TaskQueueSelectorTest, | |
| 195 TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled) { | |
| 196 selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); | |
| 197 MockObserver mock_observer; | |
| 198 selector_.SetTaskQueueSelectorObserver(&mock_observer); | |
| 199 EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(0); | |
| 200 selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::NORMAL_PRIORITY); | |
| 201 } | |
| 202 | |
| 203 TEST_F(TaskQueueSelectorTest, TestDisableEnable) { | |
| 204 MockObserver mock_observer; | |
| 205 selector_.SetTaskQueueSelectorObserver(&mock_observer); | |
| 206 | |
| 207 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 208 PushTasks(queue_order, 5); | |
| 209 DisableQueue(task_queues_[2].get()); | |
| 210 DisableQueue(task_queues_[4].get()); | |
| 211 // Disabling a queue should not affect its priority. | |
| 212 EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[2]->GetQueuePriority()); | |
| 213 EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[4]->GetQueuePriority()); | |
| 214 EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3)); | |
| 215 | |
| 216 EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2); | |
| 217 EnableQueue(task_queues_[2].get()); | |
| 218 selector_.SetQueuePriority(task_queues_[2].get(), | |
| 219 TaskQueue::BEST_EFFORT_PRIORITY); | |
| 220 EXPECT_THAT(PopTasks(), testing::ElementsAre(2)); | |
| 221 EnableQueue(task_queues_[4].get()); | |
| 222 EXPECT_THAT(PopTasks(), testing::ElementsAre(4)); | |
| 223 } | |
| 224 | |
| 225 TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) { | |
| 226 EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); | |
| 227 EXPECT_TRUE(task_queues_[2]->immediate_work_queue()->Empty()); | |
| 228 | |
| 229 DisableQueue(task_queues_[2].get()); | |
| 230 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 231 | |
| 232 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 233 PushTasks(queue_order, 5); | |
| 234 | |
| 235 EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); | |
| 236 EXPECT_FALSE(task_queues_[2]->immediate_work_queue()->Empty()); | |
| 237 EnableQueue(task_queues_[2].get()); | |
| 238 | |
| 239 EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); | |
| 240 EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); | |
| 241 } | |
| 242 | |
| 243 TEST_F(TaskQueueSelectorTest, TestEmptyQueues) { | |
| 244 WorkQueue* chosen_work_queue = nullptr; | |
| 245 EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 246 | |
| 247 // Test only disabled queues. | |
| 248 size_t queue_order[] = {0}; | |
| 249 PushTasks(queue_order, 1); | |
| 250 task_queues_[0]->SetQueueEnabled(false); | |
| 251 selector_.DisableQueue(task_queues_[0].get()); | |
| 252 EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 253 } | |
| 254 | |
| 255 TEST_F(TaskQueueSelectorTest, TestAge) { | |
| 256 size_t enqueue_order[] = {10, 1, 2, 9, 4}; | |
| 257 size_t queue_order[] = {0, 1, 2, 3, 4}; | |
| 258 PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5); | |
| 259 EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0)); | |
| 260 } | |
| 261 | |
| 262 TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) { | |
| 263 size_t queue_order[] = {0, 1, 2, 3}; | |
| 264 PushTasks(queue_order, 4); | |
| 265 selector_.SetQueuePriority(task_queues_[3].get(), | |
| 266 TaskQueue::CONTROL_PRIORITY); | |
| 267 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 268 selector_.SetQueuePriority(task_queues_[1].get(), | |
| 269 TaskQueue::BEST_EFFORT_PRIORITY); | |
| 270 for (int i = 0; i < 100; i++) { | |
| 271 WorkQueue* chosen_work_queue = nullptr; | |
| 272 EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 273 EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue()); | |
| 274 // Don't remove task from queue to simulate all queues still being full. | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) { | |
| 279 size_t queue_order[] = {0, 1, 2}; | |
| 280 PushTasks(queue_order, 3); | |
| 281 selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); | |
| 282 selector_.SetQueuePriority(task_queues_[1].get(), | |
| 283 TaskQueue::BEST_EFFORT_PRIORITY); | |
| 284 size_t counts[] = {0, 0, 0}; | |
| 285 for (int i = 0; i < 100; i++) { | |
| 286 WorkQueue* chosen_work_queue = nullptr; | |
| 287 EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 288 size_t chosen_queue_index = | |
| 289 queue_to_index_map_.find(chosen_work_queue->task_queue())->second; | |
| 290 counts[chosen_queue_index]++; | |
| 291 // Don't remove task from queue to simulate all queues still being full. | |
| 292 } | |
| 293 EXPECT_GT(counts[0], 0ul); // Check high doesn't starve normal. | |
| 294 EXPECT_GT(counts[2], counts[0]); // Check high gets more chance to run. | |
| 295 EXPECT_EQ(0ul, counts[1]); // Check best effort is starved. | |
| 296 } | |
| 297 | |
| 298 TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) { | |
| 299 size_t queue_order[] = {0, 1}; | |
| 300 PushTasks(queue_order, 2); | |
| 301 selector_.SetQueuePriority(task_queues_[0].get(), | |
| 302 TaskQueue::BEST_EFFORT_PRIORITY); | |
| 303 EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[1]->GetQueuePriority()); | |
| 304 WorkQueue* chosen_work_queue = nullptr; | |
| 305 for (int i = 0; i < 100; i++) { | |
| 306 EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 307 EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); | |
| 308 // Don't remove task from queue to simulate all queues still being full. | |
| 309 } | |
| 310 selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); | |
| 311 for (int i = 0; i < 100; i++) { | |
| 312 EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 313 EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); | |
| 314 // Don't remove task from queue to simulate all queues still being full. | |
| 315 } | |
| 316 selector_.SetQueuePriority(task_queues_[1].get(), | |
| 317 TaskQueue::CONTROL_PRIORITY); | |
| 318 for (int i = 0; i < 100; i++) { | |
| 319 EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); | |
| 320 EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); | |
| 321 // Don't remove task from queue to simulate all queues still being full. | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty) { | |
| 326 EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); | |
| 327 size_t queue_order[] = {0, 1}; | |
| 328 PushTasks(queue_order, 2); | |
| 329 | |
| 330 EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); | |
| 331 PopTasks(); | |
| 332 EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); | |
| 333 } | |
| 334 | |
| 335 TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty_ControlPriority) { | |
| 336 size_t queue_order[] = {0}; | |
| 337 PushTasks(queue_order, 1); | |
| 338 | |
| 339 selector_.SetQueuePriority(task_queues_[0].get(), | |
| 340 TaskQueue::CONTROL_PRIORITY); | |
| 341 | |
| 342 EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); | |
| 343 } | |
| 344 | |
| 345 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) { | |
| 346 WorkQueue* chosen_work_queue = nullptr; | |
| 347 bool chose_delayed_over_immediate = false; | |
| 348 EXPECT_FALSE(enabled_selector()->ChooseOldestWithPriority( | |
| 349 TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, | |
| 350 &chosen_work_queue)); | |
| 351 EXPECT_FALSE(chose_delayed_over_immediate); | |
| 352 } | |
| 353 | |
| 354 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) { | |
| 355 task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task( | |
| 356 FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); | |
| 357 | |
| 358 WorkQueue* chosen_work_queue = nullptr; | |
| 359 bool chose_delayed_over_immediate = false; | |
| 360 EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( | |
| 361 TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, | |
| 362 &chosen_work_queue)); | |
| 363 EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue()); | |
| 364 EXPECT_FALSE(chose_delayed_over_immediate); | |
| 365 } | |
| 366 | |
| 367 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) { | |
| 368 task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task( | |
| 369 FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); | |
| 370 | |
| 371 WorkQueue* chosen_work_queue = nullptr; | |
| 372 bool chose_delayed_over_immediate = false; | |
| 373 EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( | |
| 374 TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, | |
| 375 &chosen_work_queue)); | |
| 376 EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue()); | |
| 377 EXPECT_FALSE(chose_delayed_over_immediate); | |
| 378 } | |
| 379 | |
| 380 TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) { | |
| 381 TaskQueueSelectorForTest selector; | |
| 382 MockObserver mock_observer; | |
| 383 selector.SetTaskQueueSelectorObserver(&mock_observer); | |
| 384 | |
| 385 scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); | |
| 386 selector.AddQueue(task_queue.get()); | |
| 387 task_queue->SetQueueEnabled(false); | |
| 388 selector.DisableQueue(task_queue.get()); | |
| 389 | |
| 390 task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( | |
| 391 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), | |
| 392 0); | |
| 393 | |
| 394 WorkQueue* chosen_work_queue; | |
| 395 EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); | |
| 396 EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); | |
| 397 | |
| 398 task_queue->UnregisterTaskQueue(); | |
| 399 selector.RemoveQueue(task_queue.get()); | |
| 400 } | |
| 401 | |
| 402 TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) { | |
| 403 TaskQueueSelectorForTest selector; | |
| 404 MockObserver mock_observer; | |
| 405 selector.SetTaskQueueSelectorObserver(&mock_observer); | |
| 406 | |
| 407 scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); | |
| 408 scoped_refptr<TaskQueueImpl> task_queue2(NewTaskQueueWithBlockReporting()); | |
| 409 selector.AddQueue(task_queue.get()); | |
| 410 selector.AddQueue(task_queue2.get()); | |
| 411 task_queue->SetQueueEnabled(false); | |
| 412 task_queue2->SetQueueEnabled(false); | |
| 413 selector.DisableQueue(task_queue.get()); | |
| 414 selector.DisableQueue(task_queue2.get()); | |
| 415 selector.SetQueuePriority(task_queue2.get(), TaskQueue::CONTROL_PRIORITY); | |
| 416 | |
| 417 task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( | |
| 418 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), | |
| 419 0); | |
| 420 task_queue2->immediate_work_queue()->PushAndSetEnqueueOrder( | |
| 421 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), | |
| 422 0); | |
| 423 | |
| 424 // Should still only see one call to OnTriedToSelectBlockedWorkQueue. | |
| 425 WorkQueue* chosen_work_queue; | |
| 426 EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); | |
| 427 EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); | |
| 428 testing::Mock::VerifyAndClearExpectations(&mock_observer); | |
| 429 | |
| 430 // Removing the second queue and selecting again should result in another | |
| 431 // notification. | |
| 432 task_queue->UnregisterTaskQueue(); | |
| 433 selector.RemoveQueue(task_queue.get()); | |
| 434 EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); | |
| 435 EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); | |
| 436 | |
| 437 task_queue2->UnregisterTaskQueue(); | |
| 438 selector.RemoveQueue(task_queue2.get()); | |
| 439 } | |
| 440 | |
| 441 struct ChooseOldestWithPriorityTestParam { | |
| 442 int delayed_task_enqueue_order; | |
| 443 int immediate_task_enqueue_order; | |
| 444 int immediate_starvation_count; | |
| 445 const char* expected_work_queue_name; | |
| 446 bool expected_did_starve_immediate_queue; | |
| 447 }; | |
| 448 | |
| 449 static const ChooseOldestWithPriorityTestParam | |
| 450 kChooseOldestWithPriorityTestCases[] = { | |
| 451 {1, 2, 0, "delayed", true}, | |
| 452 {1, 2, 1, "delayed", true}, | |
| 453 {1, 2, 2, "delayed", true}, | |
| 454 {1, 2, 3, "immediate", false}, | |
| 455 {1, 2, 4, "immediate", false}, | |
| 456 {2, 1, 4, "immediate", false}, | |
| 457 {2, 1, 4, "immediate", false}, | |
| 458 }; | |
| 459 | |
| 460 class ChooseOldestWithPriorityTest | |
| 461 : public TaskQueueSelectorTest, | |
| 462 public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {}; | |
| 463 | |
| 464 TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) { | |
| 465 task_queues_[0]->immediate_work_queue()->Push( | |
| 466 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), | |
| 467 GetParam().immediate_task_enqueue_order, true, | |
| 468 GetParam().immediate_task_enqueue_order)); | |
| 469 | |
| 470 task_queues_[0]->delayed_work_queue()->Push( | |
| 471 TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), | |
| 472 GetParam().delayed_task_enqueue_order, true, | |
| 473 GetParam().delayed_task_enqueue_order)); | |
| 474 | |
| 475 selector_.SetImmediateStarvationCountForTest( | |
| 476 GetParam().immediate_starvation_count); | |
| 477 | |
| 478 WorkQueue* chosen_work_queue = nullptr; | |
| 479 bool chose_delayed_over_immediate = false; | |
| 480 EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( | |
| 481 TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, | |
| 482 &chosen_work_queue)); | |
| 483 EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get()); | |
| 484 EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name); | |
| 485 EXPECT_EQ(chose_delayed_over_immediate, | |
| 486 GetParam().expected_did_starve_immediate_queue); | |
| 487 } | |
| 488 | |
| 489 INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest, | |
| 490 ChooseOldestWithPriorityTest, | |
| 491 testing::ValuesIn(kChooseOldestWithPriorityTestCases)); | |
| 492 | |
| 493 } // namespace internal | |
| 494 } // namespace scheduler | |
| OLD | NEW |