1 // Copyright 2016 The Chromium Authors
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 "base/task/thread_pool/sequence.h"
6
7 #include <optional>
8 #include <utility>
9
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/test/gtest_util.h"
14 #include "base/time/time.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19 namespace internal {
20
21 namespace {
22
23 class MockTask {
24 public:
25 MOCK_METHOD0(Run, void());
26 };
27
CreateTask(MockTask * mock_task,TimeTicks now=TimeTicks::Now ())28 Task CreateTask(MockTask* mock_task, TimeTicks now = TimeTicks::Now()) {
29 return Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(mock_task)), now,
30 TimeDelta());
31 }
32
CreateDelayedTask(MockTask * mock_task,TimeDelta delay,TimeTicks now=TimeTicks::Now ())33 Task CreateDelayedTask(MockTask* mock_task,
34 TimeDelta delay,
35 TimeTicks now = TimeTicks::Now()) {
36 return Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(mock_task)), now,
37 delay);
38 }
39
ExpectMockTask(MockTask * mock_task,Task * task)40 void ExpectMockTask(MockTask* mock_task, Task* task) {
41 EXPECT_CALL(*mock_task, Run());
42 std::move(task->task).Run();
43 testing::Mock::VerifyAndClear(mock_task);
44 }
45
46 } // namespace
47
TEST(ThreadPoolSequenceTest,PushTakeRemove)48 TEST(ThreadPoolSequenceTest, PushTakeRemove) {
49 testing::StrictMock<MockTask> mock_task_a;
50 testing::StrictMock<MockTask> mock_task_b;
51 testing::StrictMock<MockTask> mock_task_c;
52 testing::StrictMock<MockTask> mock_task_d;
53 testing::StrictMock<MockTask> mock_task_e;
54
55 scoped_refptr<Sequence> sequence =
56 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
57 TaskSourceExecutionMode::kParallel);
58 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
59
60 // Push task A in the sequence. PushImmediateTask() should return true since
61 // it's the first task.
62 EXPECT_TRUE(sequence_transaction.WillPushImmediateTask());
63 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_a));
64
65 // Push task B, C and D in the sequence. PushImmediateTask() should return
66 // false since there is already a task in a sequence.
67 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
68 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_b));
69 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
70 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_c));
71 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
72 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_d));
73
74 // Take the task in front of the sequence. It should be task A.
75 auto registered_task_source =
76 RegisteredTaskSource::CreateForTesting(sequence);
77 registered_task_source.WillRunTask();
78 std::optional<Task> task =
79 registered_task_source.TakeTask(&sequence_transaction);
80 ExpectMockTask(&mock_task_a, &task.value());
81 EXPECT_FALSE(task->queue_time.is_null());
82
83 // Remove the empty slot. Task B should now be in front.
84 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
85 EXPECT_TRUE(registered_task_source.WillReEnqueue(TimeTicks::Now(),
86 &sequence_transaction));
87
88 registered_task_source.WillRunTask();
89 EXPECT_TRUE(sequence->has_worker_for_testing());
90 task = registered_task_source.TakeTask(&sequence_transaction);
91 ExpectMockTask(&mock_task_b, &task.value());
92 EXPECT_FALSE(task->queue_time.is_null());
93
94 // Remove the empty slot. Task C should now be in front.
95 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
96 EXPECT_TRUE(registered_task_source.WillReEnqueue(TimeTicks::Now(),
97 &sequence_transaction));
98
99 registered_task_source.WillRunTask();
100 EXPECT_TRUE(sequence->has_worker_for_testing());
101 task = registered_task_source.TakeTask(&sequence_transaction);
102 ExpectMockTask(&mock_task_c, &task.value());
103 EXPECT_FALSE(task->queue_time.is_null());
104
105 // Remove the empty slot.
106 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
107 EXPECT_TRUE(registered_task_source.WillReEnqueue(TimeTicks::Now(),
108 &sequence_transaction));
109 EXPECT_FALSE(sequence->has_worker_for_testing());
110
111 // Push task E in the sequence.
112 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
113 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_e));
114
115 // Task D should be in front.
116 registered_task_source.WillRunTask();
117 EXPECT_TRUE(sequence->has_worker_for_testing());
118 task = registered_task_source.TakeTask(&sequence_transaction);
119 ExpectMockTask(&mock_task_d, &task.value());
120 EXPECT_FALSE(task->queue_time.is_null());
121
122 // Remove the empty slot. Task E should now be in front.
123 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
124 EXPECT_TRUE(registered_task_source.WillReEnqueue(TimeTicks::Now(),
125 &sequence_transaction));
126 registered_task_source.WillRunTask();
127 task = registered_task_source.TakeTask(&sequence_transaction);
128 ExpectMockTask(&mock_task_e, &task.value());
129 EXPECT_FALSE(task->queue_time.is_null());
130
131 // Remove the empty slot. The sequence should now be empty.
132 EXPECT_FALSE(registered_task_source.DidProcessTask(&sequence_transaction));
133
134 // Sequence is empty and it won't be returned to the priority queue.
135 EXPECT_FALSE(sequence->has_worker_for_testing());
136 EXPECT_FALSE(sequence->is_immediate_for_testing());
137 EXPECT_TRUE(sequence->IsEmptyForTesting());
138 }
139
140 // Verifies the sort key of a BEST_EFFORT sequence that contains one task.
TEST(ThreadPoolSequenceTest,GetSortKeyBestEffort)141 TEST(ThreadPoolSequenceTest, GetSortKeyBestEffort) {
142 // Create a BEST_EFFORT sequence with a task.
143 Task best_effort_task(FROM_HERE, DoNothing(), TimeTicks::Now(), TimeDelta());
144 scoped_refptr<Sequence> best_effort_sequence =
145 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
146 TaskSourceExecutionMode::kParallel);
147 Sequence::Transaction best_effort_sequence_transaction(
148 best_effort_sequence->BeginTransaction());
149 best_effort_sequence_transaction.WillPushImmediateTask();
150 best_effort_sequence_transaction.PushImmediateTask(
151 std::move(best_effort_task));
152
153 // Get the sort key.
154 const TaskSourceSortKey best_effort_sort_key =
155 best_effort_sequence->GetSortKey();
156
157 // Take the task from the sequence, so that its sequenced time is available
158 // for the check below.
159 auto best_effort_registered_task_source =
160 RegisteredTaskSource::CreateForTesting(best_effort_sequence);
161 best_effort_registered_task_source.WillRunTask();
162 auto take_best_effort_task = best_effort_registered_task_source.TakeTask(
163 &best_effort_sequence_transaction);
164
165 // Verify the sort key.
166 EXPECT_EQ(TaskPriority::BEST_EFFORT, best_effort_sort_key.priority());
167 EXPECT_EQ(take_best_effort_task.queue_time,
168 best_effort_sort_key.ready_time());
169
170 // DidProcessTask for correctness.
171 best_effort_registered_task_source.DidProcessTask(
172 &best_effort_sequence_transaction);
173 }
174
175 // Same as ThreadPoolSequenceTest.GetSortKeyBestEffort, but with a
176 // USER_VISIBLE sequence.
TEST(ThreadPoolSequenceTest,GetSortKeyForeground)177 TEST(ThreadPoolSequenceTest, GetSortKeyForeground) {
178 // Create a USER_VISIBLE sequence with a task.
179 Task foreground_task(FROM_HERE, DoNothing(), TimeTicks::Now(), TimeDelta());
180 scoped_refptr<Sequence> foreground_sequence =
181 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE), nullptr,
182 TaskSourceExecutionMode::kParallel);
183 Sequence::Transaction foreground_sequence_transaction(
184 foreground_sequence->BeginTransaction());
185 foreground_sequence_transaction.WillPushImmediateTask();
186 foreground_sequence_transaction.PushImmediateTask(std::move(foreground_task));
187
188 // Get the sort key.
189 const TaskSourceSortKey foreground_sort_key =
190 foreground_sequence->GetSortKey();
191
192 // Take the task from the sequence, so that its sequenced time is available
193 // for the check below.
194 auto foreground_registered_task_source =
195 RegisteredTaskSource::CreateForTesting(foreground_sequence);
196 foreground_registered_task_source.WillRunTask();
197 auto take_foreground_task = foreground_registered_task_source.TakeTask(
198 &foreground_sequence_transaction);
199
200 // Verify the sort key.
201 EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority());
202 EXPECT_EQ(take_foreground_task.queue_time, foreground_sort_key.ready_time());
203
204 // DidProcessTask for correctness.
205 foreground_registered_task_source.DidProcessTask(
206 &foreground_sequence_transaction);
207 }
208
209 // Verify that a DCHECK fires if DidProcessTask() is called on a sequence which
210 // didn't return a Task.
TEST(ThreadPoolSequenceTest,DidProcessTaskWithoutWillRunTask)211 TEST(ThreadPoolSequenceTest, DidProcessTaskWithoutWillRunTask) {
212 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
213 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
214 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
215 EXPECT_TRUE(sequence_transaction.WillPushImmediateTask());
216 sequence_transaction.PushImmediateTask(
217 Task(FROM_HERE, DoNothing(), TimeTicks::Now(), TimeDelta()));
218
219 auto registered_task_source =
220 RegisteredTaskSource::CreateForTesting(sequence);
221 EXPECT_DCHECK_DEATH({
222 registered_task_source.DidProcessTask(&sequence_transaction);
223 });
224 }
225
226 // Verify that a DCHECK fires if TakeTask() is called on a sequence whose front
227 // slot is empty.
TEST(ThreadPoolSequenceTest,TakeEmptyFrontSlot)228 TEST(ThreadPoolSequenceTest, TakeEmptyFrontSlot) {
229 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
230 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
231 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
232 sequence_transaction.WillPushImmediateTask();
233 sequence_transaction.PushImmediateTask(
234 Task(FROM_HERE, DoNothing(), TimeTicks::Now(), TimeDelta()));
235
236 auto registered_task_source =
237 RegisteredTaskSource::CreateForTesting(sequence);
238 {
239 registered_task_source.WillRunTask();
240 IgnoreResult(registered_task_source.TakeTask(&sequence_transaction));
241 registered_task_source.DidProcessTask(&sequence_transaction);
242 }
243 EXPECT_DCHECK_DEATH({
244 registered_task_source.WillRunTask();
245 auto task = registered_task_source.TakeTask(&sequence_transaction);
246 });
247 }
248
249 // Verify that a DCHECK fires if TakeTask() is called on an empty sequence.
TEST(ThreadPoolSequenceTest,TakeEmptySequence)250 TEST(ThreadPoolSequenceTest, TakeEmptySequence) {
251 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
252 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
253 auto registered_task_source =
254 RegisteredTaskSource::CreateForTesting(sequence);
255 EXPECT_DCHECK_DEATH({
256 registered_task_source.WillRunTask();
257 auto task = registered_task_source.TakeTask();
258 });
259 }
260
261 // Verify that the sequence stays in worker when new tasks are being pushed
262 // while it's being processed.
TEST(ThreadPoolSequenceTest,SequenceHasWorker)263 TEST(ThreadPoolSequenceTest, SequenceHasWorker) {
264 testing::StrictMock<MockTask> mock_task_a;
265 testing::StrictMock<MockTask> mock_task_b;
266
267 scoped_refptr<Sequence> sequence =
268 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
269 TaskSourceExecutionMode::kParallel);
270
271 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
272
273 // Push task A in the sequence. WillPushImmediateTask() should return
274 // true since sequence is empty.
275 EXPECT_TRUE(sequence_transaction.WillPushImmediateTask());
276 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_a));
277
278 auto registered_task_source =
279 RegisteredTaskSource::CreateForTesting(sequence);
280
281 registered_task_source.WillRunTask();
282
283 // WillRunTask indicates that a worker has called GetWork() and is ready to
284 // run a task.
285 EXPECT_TRUE(sequence->has_worker_for_testing());
286
287 // The next task we get when we call Sequence::TakeTask should be Task A.
288 std::optional<Task> task_a =
289 registered_task_source.TakeTask(&sequence_transaction);
290
291 // Push task B into the sequence. WillPushImmediateTask() should return false.
292 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
293 sequence_transaction.PushImmediateTask(CreateTask(&mock_task_b));
294
295 // Sequence is still being processed by a worker so pushing a new task
296 // shouldn't change its location. We should expect it to still be in worker.
297 EXPECT_TRUE(sequence->has_worker_for_testing());
298
299 // Remove the empty slot. Sequence still has task B. This should return true.
300 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
301 // Sequence can run immediately.
302 EXPECT_TRUE(registered_task_source.WillReEnqueue(TimeTicks::Now(),
303 &sequence_transaction));
304
305 // Sequence is not empty so it will be returned to the priority queue.
306 EXPECT_FALSE(sequence->has_worker_for_testing());
307
308 registered_task_source.WillRunTask();
309
310 // The next task we get when we call Sequence::TakeTask should be Task B.
311 std::optional<Task> task_b =
312 registered_task_source.TakeTask(&sequence_transaction);
313
314 // Remove the empty slot. Sequence is be empty. This should return false.
315 EXPECT_FALSE(registered_task_source.DidProcessTask(&sequence_transaction));
316
317 // Sequence is empty and it won't be returned to the priority queue.
318 EXPECT_FALSE(sequence->has_worker_for_testing());
319 EXPECT_FALSE(sequence->is_immediate_for_testing());
320 EXPECT_TRUE(sequence->IsEmptyForTesting());
321 }
322
323 // Verify that the sequence handle delayed tasks.
TEST(ThreadPoolSequenceTest,PushTakeRemoveDelayedTasks)324 TEST(ThreadPoolSequenceTest, PushTakeRemoveDelayedTasks) {
325 TimeTicks now = TimeTicks::Now();
326
327 testing::StrictMock<MockTask> mock_task_a;
328 testing::StrictMock<MockTask> mock_task_b;
329 testing::StrictMock<MockTask> mock_task_c;
330 testing::StrictMock<MockTask> mock_task_d;
331
332 scoped_refptr<Sequence> sequence =
333 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
334 TaskSourceExecutionMode::kParallel);
335
336 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
337
338 // Push task A in the sequence.
339 auto delayed_task_a = CreateDelayedTask(&mock_task_a, Milliseconds(20), now);
340 // PushDelayedTask(delayed_task_a, now) should return true since sequence is
341 // empty.
342 EXPECT_TRUE(sequence_transaction.PushDelayedTask(std::move(delayed_task_a)));
343
344 // Push task B into the sequence.
345 auto delayed_task_b = CreateDelayedTask(&mock_task_b, Milliseconds(10), now);
346 // PushDelayedTask(...) should return true since task b runtime is earlier
347 // than task a's.
348 EXPECT_TRUE(sequence_transaction.PushDelayedTask(std::move(delayed_task_b)));
349
350 // Sequence doesn't have immediate tasks.
351 EXPECT_FALSE(sequence->is_immediate_for_testing());
352
353 // Time advances by 15s.
354 now += Milliseconds(15);
355
356 // Set sequence to ready
357 EXPECT_TRUE(sequence->OnBecomeReady());
358
359 // Sequence is about to be run.
360 EXPECT_TRUE(sequence->is_immediate_for_testing());
361
362 auto registered_task_source =
363 RegisteredTaskSource::CreateForTesting(sequence);
364 registered_task_source.WillRunTask();
365
366 // Take the task in front of the sequence. It should be task B.
367 std::optional<Task> task =
368 registered_task_source.TakeTask(&sequence_transaction);
369 ExpectMockTask(&mock_task_b, &task.value());
370 EXPECT_FALSE(task->queue_time.is_null());
371
372 // Remove the empty slot. Task A should now be in front. Sequence is not empty
373 // so this should return true.
374 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
375
376 // Task A is still not ready so this should return false.
377 EXPECT_FALSE(
378 registered_task_source.WillReEnqueue(now, &sequence_transaction));
379 EXPECT_FALSE(sequence->is_immediate_for_testing());
380
381 // Push task C into the sequence.
382 auto delayed_task_c = CreateDelayedTask(&mock_task_c, Milliseconds(1), now);
383 // PushDelayedTask(...) should return true since task c runtime is
384 // earlier than task a's.
385 EXPECT_TRUE(sequence_transaction.PushDelayedTask(std::move(delayed_task_c)));
386
387 // Push task D into the sequence.
388 auto delayed_task_d = CreateDelayedTask(&mock_task_d, Milliseconds(1), now);
389 // PushDelayedTask(...) should return false since task d queue time
390 // is later than task c's.
391 EXPECT_FALSE(sequence_transaction.PushDelayedTask(std::move(delayed_task_d)));
392
393 // Time advances by 2ms.
394 now += Milliseconds(2);
395 // Set sequence to ready
396 EXPECT_TRUE(registered_task_source->OnBecomeReady());
397
398 registered_task_source.WillRunTask();
399
400 // This should return task C
401 task = registered_task_source.TakeTask(&sequence_transaction);
402 ExpectMockTask(&mock_task_c, &task.value());
403 EXPECT_FALSE(task->queue_time.is_null());
404
405 // Remove the empty slot. Task D should now be in front.
406 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
407
408 // Task D is ready so this should return true.
409 EXPECT_TRUE(registered_task_source.WillReEnqueue(now, &sequence_transaction));
410 EXPECT_TRUE(sequence->is_immediate_for_testing());
411
412 registered_task_source.WillRunTask();
413
414 // This should return task D
415 task = registered_task_source.TakeTask(&sequence_transaction);
416 ExpectMockTask(&mock_task_d, &task.value());
417 EXPECT_FALSE(task->queue_time.is_null());
418
419 // Remove the empty slot. Task A should now be in front.
420 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
421
422 // Time advances by 10ms.
423 now += Milliseconds(10);
424
425 // Task A is ready so this should return true.
426 EXPECT_TRUE(registered_task_source.WillReEnqueue(now, &sequence_transaction));
427 EXPECT_TRUE(sequence->is_immediate_for_testing());
428
429 registered_task_source.WillRunTask();
430
431 // This should return task A since it's ripe
432 task = registered_task_source.TakeTask(&sequence_transaction);
433 ExpectMockTask(&mock_task_a, &task.value());
434 EXPECT_FALSE(task->queue_time.is_null());
435
436 // Remove the empty slot. Sequence should be empty now.
437 EXPECT_FALSE(registered_task_source.DidProcessTask(&sequence_transaction));
438
439 // Sequence is empty and it won't be returned to the priority queue.
440 EXPECT_FALSE(sequence->has_worker_for_testing());
441 EXPECT_FALSE(sequence->is_immediate_for_testing());
442 EXPECT_TRUE(sequence->IsEmptyForTesting());
443 }
444
445 // Verify that the sequence handle delayed and immediate tasks.
TEST(ThreadPoolSequenceTest,PushTakeRemoveMixedTasks)446 TEST(ThreadPoolSequenceTest, PushTakeRemoveMixedTasks) {
447 TimeTicks now = TimeTicks::Now();
448
449 testing::StrictMock<MockTask> mock_task_a;
450 testing::StrictMock<MockTask> mock_task_b;
451 testing::StrictMock<MockTask> mock_task_c;
452 testing::StrictMock<MockTask> mock_task_d;
453
454 scoped_refptr<Sequence> sequence =
455 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
456 TaskSourceExecutionMode::kParallel);
457
458 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
459
460 // Starting with a delayed task
461 // Push task A in the sequence.
462 auto delayed_task_a = CreateDelayedTask(&mock_task_a, Milliseconds(20), now);
463 // PushDelayedTask(delayed_task_a) should return
464 // true since sequence is empty.
465 EXPECT_TRUE(sequence_transaction.PushDelayedTask(std::move(delayed_task_a)));
466 // Sequence doesn't have immediate tasks.
467 EXPECT_FALSE(sequence->is_immediate_for_testing());
468
469 // Push an immediate task while a delayed task is already sitting in the
470 // delayed queue. This should prompt a move to the immediate queue.
471 // Push task B in the sequence.
472 auto task_b = CreateTask(&mock_task_b, now);
473 // WillPushImmediateTask() should return true since sequence is in delayed
474 // queue.
475 EXPECT_TRUE(sequence_transaction.WillPushImmediateTask());
476 sequence_transaction.PushImmediateTask(std::move(task_b));
477 // Sequence now has an immediate tasks.
478 EXPECT_TRUE(sequence->is_immediate_for_testing());
479
480 auto registered_task_source =
481 RegisteredTaskSource::CreateForTesting(sequence);
482
483 // Prepare to run a task.
484 registered_task_source.WillRunTask();
485 EXPECT_TRUE(sequence->has_worker_for_testing());
486
487 // Take the task in front of the sequence. It should be task B.
488 std::optional<Task> task =
489 registered_task_source.TakeTask(&sequence_transaction);
490 ExpectMockTask(&mock_task_b, &task.value());
491 EXPECT_FALSE(task->queue_time.is_null());
492
493 // Remove the empty slot. Task A should now be in front. Sequence is not empty
494 // so this should return true.
495 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
496
497 // Time advances by 21ms.
498 now += Milliseconds(21);
499
500 // Task A is ready so this should return true.
501 EXPECT_TRUE(registered_task_source.WillReEnqueue(now, &sequence_transaction));
502 EXPECT_TRUE(sequence->is_immediate_for_testing());
503
504 registered_task_source.WillRunTask();
505 EXPECT_TRUE(sequence->has_worker_for_testing());
506
507 // Push a delayed task while sequence is being run by a worker. Push task C in
508 // the sequence.
509 auto delayed_task_c = CreateDelayedTask(&mock_task_c, Milliseconds(5), now);
510 // PushDelayedTask(delayed_task_c) should return false since sequence is in
511 // worker.
512 EXPECT_FALSE(sequence_transaction.PushDelayedTask(std::move(delayed_task_c)));
513 // Sequence is still in worker.
514 EXPECT_TRUE(sequence->has_worker_for_testing());
515
516 // This should return task A
517 task = registered_task_source.TakeTask(&sequence_transaction);
518 ExpectMockTask(&mock_task_a, &task.value());
519 EXPECT_FALSE(task->queue_time.is_null());
520
521 // Remove the empty slot. Task C should now be in front.
522 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
523
524 // Time advances by 2ms.
525 now += Milliseconds(2);
526
527 // Task C is not ready so this should return false.
528 EXPECT_FALSE(
529 registered_task_source.WillReEnqueue(now, &sequence_transaction));
530 EXPECT_FALSE(sequence->is_immediate_for_testing());
531
532 // Time advances by 4ms. Task C becomes ready.
533 now += Milliseconds(4);
534
535 // Set sequence to ready
536 EXPECT_TRUE(registered_task_source->OnBecomeReady());
537 EXPECT_TRUE(sequence->is_immediate_for_testing());
538
539 // Push task D in the sequence while sequence is ready.
540 auto task_d = CreateTask(&mock_task_d, now);
541 // WillPushImmediateTask() should return false since sequence is already in
542 // immediate queue.
543 EXPECT_FALSE(sequence_transaction.WillPushImmediateTask());
544 sequence_transaction.PushImmediateTask(std::move(task_d));
545 EXPECT_TRUE(sequence->is_immediate_for_testing());
546
547 registered_task_source.WillRunTask();
548 EXPECT_TRUE(sequence->has_worker_for_testing());
549
550 // This should return task C since was ready before Task D was posted.
551 task = registered_task_source.TakeTask(&sequence_transaction);
552 ExpectMockTask(&mock_task_c, &task.value());
553 EXPECT_FALSE(task->queue_time.is_null());
554
555 // Remove the empty slot. Task D should now be in front.
556 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
557
558 // Task D should be run so this should return true.
559 EXPECT_TRUE(registered_task_source.WillReEnqueue(now, &sequence_transaction));
560 EXPECT_TRUE(sequence->is_immediate_for_testing());
561
562 registered_task_source.WillRunTask();
563
564 // This should return task D since it's immediate.
565 task = registered_task_source.TakeTask(&sequence_transaction);
566 ExpectMockTask(&mock_task_d, &task.value());
567 EXPECT_FALSE(task->queue_time.is_null());
568
569 // Remove the empty slot. Sequence should be empty.
570 EXPECT_FALSE(registered_task_source.DidProcessTask(&sequence_transaction));
571 EXPECT_FALSE(sequence->has_worker_for_testing());
572 EXPECT_FALSE(sequence->is_immediate_for_testing());
573 }
574
575 // Test that PushDelayedTask method is used only for delayed tasks
TEST(ThreadPoolSequenceTest,TestPushDelayedTaskMethodUsage)576 TEST(ThreadPoolSequenceTest, TestPushDelayedTaskMethodUsage) {
577 testing::StrictMock<MockTask> mock_task_a;
578
579 scoped_refptr<Sequence> sequence =
580 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
581 TaskSourceExecutionMode::kParallel);
582
583 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
584
585 // Push task B in the sequence.
586 auto task_a = CreateTask(&mock_task_a);
587 EXPECT_DCHECK_DEATH(
588 { sequence_transaction.PushDelayedTask(std::move(task_a)); });
589 }
590
591 // Verifies the delayed sort key of a sequence that contains one delayed task.
592 // We will also test for the case where we push a delayed task with a runtime
593 // earlier than the queue_time of an already pushed immediate task.
TEST(ThreadPoolSequenceTest,GetDelayedSortKeyMixedtasks)594 TEST(ThreadPoolSequenceTest, GetDelayedSortKeyMixedtasks) {
595 TimeTicks now = TimeTicks::Now();
596
597 testing::StrictMock<MockTask> mock_task_a;
598 testing::StrictMock<MockTask> mock_task_b;
599
600 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
601 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
602 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
603
604 // Create a first delayed task.
605 EXPECT_TRUE(sequence_transaction.PushDelayedTask(
606 CreateDelayedTask(&mock_task_a, Milliseconds(10), now)));
607
608 // Get the delayed sort key (first time).
609 const TimeTicks sort_key_1 = sequence->GetDelayedSortKey();
610
611 // Time advances by 11ms.
612 now += Milliseconds(11);
613
614 // Push an immediate task that should run after the delayed task.
615 auto immediate_task = CreateTask(&mock_task_b, now);
616 sequence_transaction.WillPushImmediateTask();
617 sequence_transaction.PushImmediateTask(std::move(immediate_task));
618
619 // Get the delayed sort key (second time).
620 const TimeTicks sort_key_2 = sequence->GetDelayedSortKey();
621
622 // Take the delayed task from the sequence, so that its next delayed runtime
623 // is available for the check below.
624 auto registered_task_source =
625 RegisteredTaskSource::CreateForTesting(sequence);
626 registered_task_source.WillRunTask();
627 std::optional<Task> take_delayed_task =
628 registered_task_source.TakeTask(&sequence_transaction);
629 ExpectMockTask(&mock_task_a, &take_delayed_task.value());
630 EXPECT_FALSE(take_delayed_task->queue_time.is_null());
631
632 // For correctness.
633 registered_task_source.DidProcessTask(&sequence_transaction);
634 registered_task_source.WillReEnqueue(now, &sequence_transaction);
635
636 // Verify that sort_key_1 is equal to the delayed task latest run time.
637 EXPECT_EQ(take_delayed_task->latest_delayed_run_time(), sort_key_1);
638
639 // Verify that the sort key didn't change after pushing the immediate task.
640 EXPECT_EQ(sort_key_1, sort_key_2);
641
642 // Get the delayed sort key (third time).
643 const TimeTicks sort_key_3 = sequence->GetDelayedSortKey();
644
645 // Take the immediate task from the sequence, so that its queue time
646 // is available for the check below.
647 registered_task_source.WillRunTask();
648 std::optional<Task> take_immediate_task =
649 registered_task_source.TakeTask(&sequence_transaction);
650 ExpectMockTask(&mock_task_b, &take_immediate_task.value());
651 EXPECT_FALSE(take_immediate_task->queue_time.is_null());
652
653 // Verify that sort_key_1 is equal to the immediate task queue time.
654 EXPECT_EQ(take_immediate_task->queue_time, sort_key_3);
655
656 // DidProcessTask for correctness.
657 registered_task_source.DidProcessTask(&sequence_transaction);
658 }
659
660 // Test for the case where we push a delayed task to run earlier than the
661 // already posted delayed task.
TEST(ThreadPoolSequenceTest,GetDelayedSortKeyDelayedtasks)662 TEST(ThreadPoolSequenceTest, GetDelayedSortKeyDelayedtasks) {
663 TimeTicks now = TimeTicks::Now();
664
665 testing::StrictMock<MockTask> mock_task_a;
666 testing::StrictMock<MockTask> mock_task_b;
667
668 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
669 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
670 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
671
672 // Create a first delayed task.
673 sequence_transaction.PushDelayedTask(
674 CreateDelayedTask(&mock_task_a, Milliseconds(15), now));
675
676 // Get the delayed sort key (first time).
677 const TimeTicks sort_key_1 = sequence->GetDelayedSortKey();
678
679 // Create a first delayed task.
680 sequence_transaction.PushDelayedTask(
681 CreateDelayedTask(&mock_task_b, Milliseconds(10), now));
682
683 // Get the delayed sort key (second time).
684 const TimeTicks sort_key_2 = sequence->GetDelayedSortKey();
685
686 // Time advances by 11ms
687 now += Milliseconds(11);
688
689 sequence->OnBecomeReady();
690 auto registered_task_source =
691 RegisteredTaskSource::CreateForTesting(sequence);
692 registered_task_source.WillRunTask();
693 std::optional<Task> task =
694 registered_task_source.TakeTask(&sequence_transaction);
695 ExpectMockTask(&mock_task_b, &task.value());
696 EXPECT_FALSE(task->queue_time.is_null());
697
698 // Verify that sort_key_2 is equal to the last posted task latest delayed run
699 // time.
700 EXPECT_EQ(task->latest_delayed_run_time(), sort_key_2);
701
702 // Time advances by 5ms
703 now += Milliseconds(5);
704
705 // For correctness.
706 registered_task_source.DidProcessTask(&sequence_transaction);
707 registered_task_source.WillReEnqueue(now, &sequence_transaction);
708
709 registered_task_source.WillRunTask();
710 task = registered_task_source.TakeTask(&sequence_transaction);
711 ExpectMockTask(&mock_task_a, &task.value());
712 EXPECT_FALSE(task->queue_time.is_null());
713
714 // Verify that sort_key_1 is equal to the first posted task latest delayed run
715 // time.
716 EXPECT_EQ(task->latest_delayed_run_time(), sort_key_1);
717
718 // DidProcessTask for correctness.
719 registered_task_source.DidProcessTask(&sequence_transaction);
720 }
721
722 } // namespace internal
723 } // namespace base
724