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 |