xref: /aosp_15_r20/external/cronet/base/task/thread_pool/sequence_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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