xref: /aosp_15_r20/external/cronet/base/task/thread_pool/job_task_source_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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/job_task_source.h"
6 
7 #include <utility>
8 
9 #include "base/functional/callback_helpers.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/task/thread_pool/pooled_task_runner_delegate.h"
12 #include "base/task/thread_pool/test_utils.h"
13 #include "base/test/bind.h"
14 #include "base/test/gtest_util.h"
15 #include "base/test/test_timeouts.h"
16 #include "build/build_config.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 using ::testing::_;
21 using ::testing::Return;
22 
23 namespace base {
24 namespace internal {
25 
26 class MockPooledTaskRunnerDelegate : public PooledTaskRunnerDelegate {
27  public:
28   MOCK_METHOD2(PostTaskWithSequence,
29                bool(Task task, scoped_refptr<Sequence> sequence));
30   MOCK_METHOD1(ShouldYield, bool(const TaskSource* task_source));
31   MOCK_METHOD1(EnqueueJobTaskSource,
32                bool(scoped_refptr<JobTaskSource> task_source));
33   MOCK_METHOD1(RemoveJobTaskSource,
34                void(scoped_refptr<JobTaskSource> task_source));
35   MOCK_CONST_METHOD1(IsRunningPoolWithTraits, bool(const TaskTraits& traits));
36   MOCK_METHOD2(UpdatePriority,
37                void(scoped_refptr<TaskSource> task_source,
38                     TaskPriority priority));
39   MOCK_METHOD2(UpdateJobPriority,
40                void(scoped_refptr<TaskSource> task_source,
41                     TaskPriority priority));
42 };
43 
44 class ThreadPoolJobTaskSourceTest : public testing::Test {
45  protected:
46   testing::StrictMock<MockPooledTaskRunnerDelegate>
47       pooled_task_runner_delegate_;
48 };
49 
50 // Verifies the normal flow of running 2 tasks one after the other.
TEST_F(ThreadPoolJobTaskSourceTest,RunTasks)51 TEST_F(ThreadPoolJobTaskSourceTest, RunTasks) {
52   auto job_task = base::MakeRefCounted<test::MockJobTask>(
53       DoNothing(), /* num_tasks_to_run */ 2);
54   scoped_refptr<JobTaskSource> task_source =
55       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
56   auto registered_task_source =
57       RegisteredTaskSource::CreateForTesting(task_source);
58 
59   EXPECT_EQ(2U, task_source->GetRemainingConcurrency());
60   {
61     EXPECT_EQ(registered_task_source.WillRunTask(),
62               TaskSource::RunStatus::kAllowedNotSaturated);
63     EXPECT_EQ(1U, task_source->GetWorkerCount());
64 
65     auto task = registered_task_source.TakeTask();
66     std::move(task.task).Run();
67     EXPECT_TRUE(registered_task_source.DidProcessTask());
68     EXPECT_EQ(0U, task_source->GetWorkerCount());
69   }
70   {
71     EXPECT_EQ(registered_task_source.WillRunTask(),
72               TaskSource::RunStatus::kAllowedSaturated);
73     EXPECT_EQ(1U, task_source->GetWorkerCount());
74 
75     // An attempt to run an additional task is not allowed.
76     EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
77               TaskSource::RunStatus::kDisallowed);
78     EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
79     auto task = registered_task_source.TakeTask();
80     EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
81               TaskSource::RunStatus::kDisallowed);
82 
83     std::move(task.task).Run();
84     EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
85     EXPECT_TRUE(task_source->IsActive());
86     // Returns false because the task source is out of tasks.
87     EXPECT_FALSE(registered_task_source.DidProcessTask());
88     EXPECT_EQ(0U, task_source->GetWorkerCount());
89     EXPECT_FALSE(task_source->IsActive());
90   }
91 }
92 
93 // Verifies that a job task source doesn't allow any new RunStatus after Clear()
94 // is called.
TEST_F(ThreadPoolJobTaskSourceTest,Clear)95 TEST_F(ThreadPoolJobTaskSourceTest, Clear) {
96   auto job_task = base::MakeRefCounted<test::MockJobTask>(
97       DoNothing(), /* num_tasks_to_run */ 5);
98   scoped_refptr<JobTaskSource> task_source =
99       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
100 
101   EXPECT_EQ(5U, task_source->GetRemainingConcurrency());
102   auto registered_task_source_a =
103       RegisteredTaskSource::CreateForTesting(task_source);
104   EXPECT_EQ(registered_task_source_a.WillRunTask(),
105             TaskSource::RunStatus::kAllowedNotSaturated);
106   auto task_a = registered_task_source_a.TakeTask();
107 
108   auto registered_task_source_b =
109       RegisteredTaskSource::CreateForTesting(task_source);
110   EXPECT_EQ(registered_task_source_b.WillRunTask(),
111             TaskSource::RunStatus::kAllowedNotSaturated);
112 
113   auto registered_task_source_c =
114       RegisteredTaskSource::CreateForTesting(task_source);
115   EXPECT_EQ(registered_task_source_c.WillRunTask(),
116             TaskSource::RunStatus::kAllowedNotSaturated);
117 
118   auto registered_task_source_d =
119       RegisteredTaskSource::CreateForTesting(task_source);
120   EXPECT_EQ(registered_task_source_d.WillRunTask(),
121             TaskSource::RunStatus::kAllowedNotSaturated);
122 
123   EXPECT_FALSE(task_source->ShouldYield());
124 
125   {
126     EXPECT_EQ(1U, task_source->GetRemainingConcurrency());
127     auto task = registered_task_source_c.Clear();
128     EXPECT_FALSE(task);
129     registered_task_source_c.DidProcessTask();
130     EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
131   }
132   // The task source shouldn't allow any further tasks after Clear.
133   EXPECT_TRUE(task_source->ShouldYield());
134   EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
135             TaskSource::RunStatus::kDisallowed);
136 
137   // Another outstanding RunStatus can still call Clear.
138   {
139     auto task = registered_task_source_d.Clear();
140     EXPECT_FALSE(task);
141     registered_task_source_d.DidProcessTask();
142     EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
143   }
144 
145   // A task that was already acquired can still run.
146   std::move(task_a.task).Run();
147   registered_task_source_a.DidProcessTask();
148 
149   // A valid outstanding RunStatus can also take and run a task.
150   {
151     auto task = registered_task_source_b.TakeTask();
152     std::move(task.task).Run();
153     registered_task_source_b.DidProcessTask();
154   }
155 }
156 
157 // Verifies that a job task source doesn't return an "allowed" RunStatus after
158 // Cancel() is called.
TEST_F(ThreadPoolJobTaskSourceTest,Cancel)159 TEST_F(ThreadPoolJobTaskSourceTest, Cancel) {
160   auto job_task = base::MakeRefCounted<test::MockJobTask>(
161       DoNothing(), /* num_tasks_to_run */ 3);
162   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
163       FROM_HERE, {TaskPriority::BEST_EFFORT}, &pooled_task_runner_delegate_);
164 
165   auto registered_task_source_a =
166       RegisteredTaskSource::CreateForTesting(task_source);
167   EXPECT_EQ(registered_task_source_a.WillRunTask(),
168             TaskSource::RunStatus::kAllowedNotSaturated);
169   auto task_a = registered_task_source_a.TakeTask();
170 
171   auto registered_task_source_b =
172       RegisteredTaskSource::CreateForTesting(task_source);
173   EXPECT_EQ(registered_task_source_b.WillRunTask(),
174             TaskSource::RunStatus::kAllowedNotSaturated);
175 
176   EXPECT_FALSE(task_source->ShouldYield());
177 
178   task_source->Cancel();
179   EXPECT_TRUE(task_source->ShouldYield());
180 
181   // The task source shouldn't allow any further tasks after Cancel.
182   EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
183             TaskSource::RunStatus::kDisallowed);
184 
185   // A task that was already acquired can still run.
186   std::move(task_a.task).Run();
187   registered_task_source_a.DidProcessTask();
188 
189   // A RegisteredTaskSource that's ready can also take and run a task.
190   {
191     auto task = registered_task_source_b.TakeTask();
192     std::move(task.task).Run();
193     registered_task_source_b.DidProcessTask();
194   }
195 }
196 
197 // Verifies that multiple tasks can run in parallel up to |max_concurrency|.
TEST_F(ThreadPoolJobTaskSourceTest,RunTasksInParallel)198 TEST_F(ThreadPoolJobTaskSourceTest, RunTasksInParallel) {
199   auto job_task = base::MakeRefCounted<test::MockJobTask>(
200       DoNothing(), /* num_tasks_to_run */ 2);
201   scoped_refptr<JobTaskSource> task_source =
202       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
203 
204   auto registered_task_source_a =
205       RegisteredTaskSource::CreateForTesting(task_source);
206   EXPECT_EQ(registered_task_source_a.WillRunTask(),
207             TaskSource::RunStatus::kAllowedNotSaturated);
208   EXPECT_EQ(1U, task_source->GetWorkerCount());
209   EXPECT_EQ(1U, task_source->GetSortKey().worker_count());
210   auto task_a = registered_task_source_a.TakeTask();
211 
212   auto registered_task_source_b =
213       RegisteredTaskSource::CreateForTesting(task_source);
214   EXPECT_EQ(registered_task_source_b.WillRunTask(),
215             TaskSource::RunStatus::kAllowedSaturated);
216   EXPECT_EQ(2U, task_source->GetWorkerCount());
217   EXPECT_EQ(2U, task_source->GetSortKey().worker_count());
218   auto task_b = registered_task_source_b.TakeTask();
219 
220   // WillRunTask() should return a null RunStatus once the max concurrency is
221   // reached.
222   EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
223             TaskSource::RunStatus::kDisallowed);
224 
225   std::move(task_a.task).Run();
226   // Adding a task before closing the first run operation should cause the task
227   // source to re-enqueue.
228   job_task->SetNumTasksToRun(2);
229   EXPECT_TRUE(registered_task_source_a.DidProcessTask());
230   EXPECT_EQ(1U, task_source->GetSortKey().worker_count());
231 
232   std::move(task_b.task).Run();
233   EXPECT_TRUE(registered_task_source_b.DidProcessTask());
234   EXPECT_EQ(0U, task_source->GetSortKey().worker_count());
235 
236   EXPECT_EQ(0U, task_source->GetWorkerCount());
237 
238   auto registered_task_source_c =
239       RegisteredTaskSource::CreateForTesting(task_source);
240   EXPECT_EQ(registered_task_source_c.WillRunTask(),
241             TaskSource::RunStatus::kAllowedSaturated);
242   auto task_c = registered_task_source_c.TakeTask();
243 
244   std::move(task_c.task).Run();
245   EXPECT_FALSE(registered_task_source_c.DidProcessTask());
246 }
247 
248 // Verifies the normal flow of running the join task until completion.
TEST_F(ThreadPoolJobTaskSourceTest,RunJoinTask)249 TEST_F(ThreadPoolJobTaskSourceTest, RunJoinTask) {
250   auto job_task = base::MakeRefCounted<test::MockJobTask>(
251       DoNothing(), /* num_tasks_to_run */ 2);
252   scoped_refptr<JobTaskSource> task_source =
253       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
254 
255   EXPECT_TRUE(task_source->WillJoin());
256   // Intentionally run |worker_task| twice to make sure RunJoinTask() calls
257   // it again. This can happen in production if the joining thread spuriously
258   // return and needs to run again.
259   EXPECT_TRUE(task_source->RunJoinTask());
260   EXPECT_FALSE(task_source->RunJoinTask());
261 }
262 
263 // Verify that |worker_count| excludes the (inactive) returning thread calling
264 // max_concurrency_callback.
TEST_F(ThreadPoolJobTaskSourceTest,RunTaskWorkerCount)265 TEST_F(ThreadPoolJobTaskSourceTest, RunTaskWorkerCount) {
266   size_t max_concurrency = 1;
267   scoped_refptr<JobTaskSource> task_source =
268       base::MakeRefCounted<JobTaskSource>(
269           FROM_HERE, TaskTraits(),
270           BindLambdaForTesting(
271               [&](JobDelegate* delegate) { --max_concurrency; }),
272           BindLambdaForTesting([&](size_t worker_count) -> size_t {
273             return max_concurrency + worker_count;
274           }),
275           &pooled_task_runner_delegate_);
276 
277   auto registered_task_source =
278       RegisteredTaskSource::CreateForTesting(task_source);
279 
280   EXPECT_EQ(registered_task_source.WillRunTask(),
281             TaskSource::RunStatus::kAllowedSaturated);
282   auto task = registered_task_source.TakeTask();
283   std::move(task.task).Run();
284   // Once the worker_task runs, |worker_count| should drop to 0 and the job
285   // should finish.
286   EXPECT_FALSE(registered_task_source.DidProcessTask());
287   EXPECT_EQ(0U, max_concurrency);
288 }
289 
290 // Verify that |worker_count| excludes the (inactive) joining thread calling
291 // max_concurrency_callback.
TEST_F(ThreadPoolJobTaskSourceTest,RunJoinTaskWorkerCount)292 TEST_F(ThreadPoolJobTaskSourceTest, RunJoinTaskWorkerCount) {
293   size_t max_concurrency = 1;
294   scoped_refptr<JobTaskSource> task_source =
295       base::MakeRefCounted<JobTaskSource>(
296           FROM_HERE, TaskTraits(),
297           BindLambdaForTesting(
298               [&](JobDelegate* delegate) { --max_concurrency; }),
299           BindLambdaForTesting([&](size_t worker_count) -> size_t {
300             return max_concurrency + worker_count;
301           }),
302           &pooled_task_runner_delegate_);
303 
304   EXPECT_TRUE(task_source->WillJoin());
305   // Once the worker_task runs, |worker_count| should drop to 0 and the job
306   // should finish.
307   EXPECT_FALSE(task_source->RunJoinTask());
308   EXPECT_EQ(0U, max_concurrency);
309 }
310 
311 // Verifies that WillJoin() doesn't allow a joining thread to contribute
312 // after Cancel() is called.
TEST_F(ThreadPoolJobTaskSourceTest,CancelJoinTask)313 TEST_F(ThreadPoolJobTaskSourceTest, CancelJoinTask) {
314   auto job_task = base::MakeRefCounted<test::MockJobTask>(
315       DoNothing(), /* num_tasks_to_run */ 2);
316   scoped_refptr<JobTaskSource> task_source =
317       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
318 
319   task_source->Cancel();
320   EXPECT_FALSE(task_source->WillJoin());
321 }
322 
323 // Verifies that RunJoinTask() doesn't allow a joining thread to contribute
324 // after Cancel() is called.
TEST_F(ThreadPoolJobTaskSourceTest,JoinCancelTask)325 TEST_F(ThreadPoolJobTaskSourceTest, JoinCancelTask) {
326   auto job_task = base::MakeRefCounted<test::MockJobTask>(
327       DoNothing(), /* num_tasks_to_run */ 2);
328   scoped_refptr<JobTaskSource> task_source =
329       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
330 
331   EXPECT_TRUE(task_source->WillJoin());
332   task_source->Cancel();
333   EXPECT_FALSE(task_source->RunJoinTask());
334 }
335 
336 // Verifies that the join task can run in parallel with worker tasks up to
337 // |max_concurrency|.
TEST_F(ThreadPoolJobTaskSourceTest,RunJoinTaskInParallel)338 TEST_F(ThreadPoolJobTaskSourceTest, RunJoinTaskInParallel) {
339   auto job_task = base::MakeRefCounted<test::MockJobTask>(
340       DoNothing(), /* num_tasks_to_run */ 2);
341   scoped_refptr<JobTaskSource> task_source =
342       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
343 
344   auto registered_task_source =
345       RegisteredTaskSource::CreateForTesting(task_source);
346   EXPECT_EQ(registered_task_source.WillRunTask(),
347             TaskSource::RunStatus::kAllowedNotSaturated);
348   auto worker_task = registered_task_source.TakeTask();
349 
350   EXPECT_TRUE(task_source->WillJoin());
351   EXPECT_TRUE(task_source->IsActive());
352 
353   std::move(worker_task.task).Run();
354   EXPECT_FALSE(registered_task_source.DidProcessTask());
355 
356   EXPECT_FALSE(task_source->RunJoinTask());
357   EXPECT_FALSE(task_source->IsActive());
358 }
359 
360 // Verifies that a call to NotifyConcurrencyIncrease() calls the delegate
361 // and allows to run additional tasks.
TEST_F(ThreadPoolJobTaskSourceTest,NotifyConcurrencyIncrease)362 TEST_F(ThreadPoolJobTaskSourceTest, NotifyConcurrencyIncrease) {
363   auto job_task = base::MakeRefCounted<test::MockJobTask>(
364       DoNothing(), /* num_tasks_to_run */ 1);
365   scoped_refptr<JobTaskSource> task_source =
366       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
367 
368   auto registered_task_source_a =
369       RegisteredTaskSource::CreateForTesting(task_source);
370   EXPECT_EQ(registered_task_source_a.WillRunTask(),
371             TaskSource::RunStatus::kAllowedSaturated);
372   auto task_a = registered_task_source_a.TakeTask();
373   EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
374             TaskSource::RunStatus::kDisallowed);
375 
376   job_task->SetNumTasksToRun(2);
377   EXPECT_CALL(pooled_task_runner_delegate_, EnqueueJobTaskSource(_)).Times(1);
378   task_source->NotifyConcurrencyIncrease();
379 
380   auto registered_task_source_b =
381       RegisteredTaskSource::CreateForTesting(task_source);
382   // WillRunTask() should return a valid RunStatus because max concurrency was
383   // increased to 2.
384   EXPECT_EQ(registered_task_source_b.WillRunTask(),
385             TaskSource::RunStatus::kAllowedSaturated);
386   auto task_b = registered_task_source_b.TakeTask();
387   EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
388             TaskSource::RunStatus::kDisallowed);
389 
390   std::move(task_a.task).Run();
391   EXPECT_FALSE(registered_task_source_a.DidProcessTask());
392 
393   std::move(task_b.task).Run();
394   EXPECT_FALSE(registered_task_source_b.DidProcessTask());
395 }
396 
397 // Verifies that ShouldYield() calls the delegate.
TEST_F(ThreadPoolJobTaskSourceTest,ShouldYield)398 TEST_F(ThreadPoolJobTaskSourceTest, ShouldYield) {
399   auto job_task = base::MakeRefCounted<test::MockJobTask>(
400       BindLambdaForTesting([](JobDelegate* delegate) {
401         // As set up below, the mock will return false once and true the second
402         // time.
403         EXPECT_FALSE(delegate->ShouldYield());
404         EXPECT_TRUE(delegate->ShouldYield());
405       }),
406       /* num_tasks_to_run */ 1);
407   scoped_refptr<JobTaskSource> task_source =
408       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
409 
410   auto registered_task_source =
411       RegisteredTaskSource::CreateForTesting(task_source);
412   ASSERT_EQ(registered_task_source.WillRunTask(),
413             TaskSource::RunStatus::kAllowedSaturated);
414 
415   auto task = registered_task_source.TakeTask();
416 
417   EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_))
418       .Times(2)
419       .WillOnce(Return(false))
420       .WillOnce(Return(true));
421 
422   std::move(task.task).Run();
423   EXPECT_FALSE(registered_task_source.DidProcessTask());
424 }
425 
426 // Verifies that max concurrency is allowed to stagnate when ShouldYield returns
427 // true.
TEST_F(ThreadPoolJobTaskSourceTest,MaxConcurrencyStagnateIfShouldYield)428 TEST_F(ThreadPoolJobTaskSourceTest, MaxConcurrencyStagnateIfShouldYield) {
429   scoped_refptr<JobTaskSource> task_source =
430       base::MakeRefCounted<JobTaskSource>(
431           FROM_HERE, TaskTraits(), BindRepeating([](JobDelegate* delegate) {
432             // As set up below, the mock will return true once.
433             ASSERT_TRUE(delegate->ShouldYield());
434           }),
435           BindRepeating([](size_t /*worker_count*/) -> size_t {
436             return 1;  // max concurrency is always 1.
437           }),
438           &pooled_task_runner_delegate_);
439 
440   EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_))
441       .WillOnce(Return(true));
442 
443   auto registered_task_source =
444       RegisteredTaskSource::CreateForTesting(task_source);
445   ASSERT_EQ(registered_task_source.WillRunTask(),
446             TaskSource::RunStatus::kAllowedSaturated);
447   auto task = registered_task_source.TakeTask();
448 
449   // Running the task should not fail even though max concurrency remained at 1,
450   // since ShouldYield() returned true.
451   std::move(task.task).Run();
452   registered_task_source.DidProcessTask();
453 }
454 
TEST_F(ThreadPoolJobTaskSourceTest,InvalidTakeTask)455 TEST_F(ThreadPoolJobTaskSourceTest, InvalidTakeTask) {
456   auto job_task =
457       base::MakeRefCounted<test::MockJobTask>(DoNothing(),
458                                               /* num_tasks_to_run */ 1);
459   scoped_refptr<JobTaskSource> task_source =
460       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
461 
462   auto registered_task_source_a =
463       RegisteredTaskSource::CreateForTesting(task_source);
464   EXPECT_EQ(registered_task_source_a.WillRunTask(),
465             TaskSource::RunStatus::kAllowedSaturated);
466 
467   auto registered_task_source_b =
468       RegisteredTaskSource::CreateForTesting(task_source);
469   EXPECT_EQ(registered_task_source_b.WillRunTask(),
470             TaskSource::RunStatus::kDisallowed);
471 
472   // Can not be called with an invalid RunStatus.
473   EXPECT_DCHECK_DEATH({ auto task = registered_task_source_b.TakeTask(); });
474 
475   auto task = registered_task_source_a.TakeTask();
476   registered_task_source_a.DidProcessTask();
477 }
478 
TEST_F(ThreadPoolJobTaskSourceTest,InvalidDidProcessTask)479 TEST_F(ThreadPoolJobTaskSourceTest, InvalidDidProcessTask) {
480   auto job_task =
481       base::MakeRefCounted<test::MockJobTask>(DoNothing(),
482                                               /* num_tasks_to_run */ 1);
483   scoped_refptr<JobTaskSource> task_source =
484       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
485 
486   auto registered_task_source =
487       RegisteredTaskSource::CreateForTesting(task_source);
488 
489   // Can not be called before WillRunTask().
490   EXPECT_DCHECK_DEATH(registered_task_source.DidProcessTask());
491 }
492 
TEST_F(ThreadPoolJobTaskSourceTest,AcquireTaskId)493 TEST_F(ThreadPoolJobTaskSourceTest, AcquireTaskId) {
494   auto job_task =
495       base::MakeRefCounted<test::MockJobTask>(DoNothing(),
496                                               /* num_tasks_to_run */ 4);
497   scoped_refptr<JobTaskSource> task_source =
498       job_task->GetJobTaskSource(FROM_HERE, {}, &pooled_task_runner_delegate_);
499 
500   EXPECT_EQ(0U, task_source->AcquireTaskId());
501   EXPECT_EQ(1U, task_source->AcquireTaskId());
502   EXPECT_EQ(2U, task_source->AcquireTaskId());
503   EXPECT_EQ(3U, task_source->AcquireTaskId());
504   EXPECT_EQ(4U, task_source->AcquireTaskId());
505   task_source->ReleaseTaskId(1);
506   task_source->ReleaseTaskId(3);
507   EXPECT_EQ(1U, task_source->AcquireTaskId());
508   EXPECT_EQ(3U, task_source->AcquireTaskId());
509   EXPECT_EQ(5U, task_source->AcquireTaskId());
510 }
511 
512 // Verifies that task id is released after worker_task returns.
TEST_F(ThreadPoolJobTaskSourceTest,GetTaskId)513 TEST_F(ThreadPoolJobTaskSourceTest, GetTaskId) {
514   auto task_source = MakeRefCounted<JobTaskSource>(
515       FROM_HERE, TaskTraits{}, BindRepeating([](JobDelegate* delegate) {
516         // Confirm that task id 0 is reused on the second run.
517         EXPECT_EQ(0U, delegate->GetTaskId());
518 
519         // Allow running the task again.
520         delegate->NotifyConcurrencyIncrease();
521       }),
522       BindRepeating([](size_t /*worker_count*/) -> size_t { return 1; }),
523       &pooled_task_runner_delegate_);
524 
525   auto registered_task_source =
526       RegisteredTaskSource::CreateForTesting(task_source);
527 
528   // Run the worker_task twice.
529   ASSERT_EQ(registered_task_source.WillRunTask(),
530             TaskSource::RunStatus::kAllowedSaturated);
531   auto task1 = registered_task_source.TakeTask();
532   std::move(task1.task).Run();
533   registered_task_source.DidProcessTask();
534 
535   ASSERT_EQ(registered_task_source.WillRunTask(),
536             TaskSource::RunStatus::kAllowedSaturated);
537   auto task2 = registered_task_source.TakeTask();
538   std::move(task2.task).Run();
539   registered_task_source.DidProcessTask();
540 }
541 
542 }  // namespace internal
543 }  // namespace base
544