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/test_task_factory.h"
6
7 #include "base/check_op.h"
8 #include "base/functional/bind.h"
9 #include "base/functional/callback.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18 namespace internal {
19 namespace test {
20
TestTaskFactory(scoped_refptr<TaskRunner> task_runner,TaskSourceExecutionMode execution_mode)21 TestTaskFactory::TestTaskFactory(scoped_refptr<TaskRunner> task_runner,
22 TaskSourceExecutionMode execution_mode)
23 : cv_(&lock_),
24 task_runner_(std::move(task_runner)),
25 execution_mode_(execution_mode) {
26 // Detach |thread_checker_| from the current thread. It will be attached to
27 // the first thread that calls ThreadCheckerImpl::CalledOnValidThread().
28 thread_checker_.DetachFromThread();
29 }
30
~TestTaskFactory()31 TestTaskFactory::~TestTaskFactory() {
32 WaitForAllTasksToRun();
33 }
34
PostTask(PostNestedTask post_nested_task,OnceClosure after_task_closure)35 bool TestTaskFactory::PostTask(PostNestedTask post_nested_task,
36 OnceClosure after_task_closure) {
37 AutoLock auto_lock(lock_);
38 return task_runner_->PostTask(
39 FROM_HERE, BindOnce(&TestTaskFactory::RunTaskCallback, Unretained(this),
40 num_posted_tasks_++, post_nested_task,
41 std::move(after_task_closure)));
42 }
43
WaitForAllTasksToRun() const44 void TestTaskFactory::WaitForAllTasksToRun() const {
45 AutoLock auto_lock(lock_);
46 while (ran_tasks_.size() < num_posted_tasks_)
47 cv_.Wait();
48 }
49
RunTaskCallback(size_t task_index,PostNestedTask post_nested_task,OnceClosure after_task_closure)50 void TestTaskFactory::RunTaskCallback(size_t task_index,
51 PostNestedTask post_nested_task,
52 OnceClosure after_task_closure) {
53 if (post_nested_task == PostNestedTask::YES)
54 PostTask(PostNestedTask::NO, OnceClosure());
55
56 if (execution_mode_ == TaskSourceExecutionMode::kSingleThread ||
57 execution_mode_ == TaskSourceExecutionMode::kSequenced) {
58 EXPECT_TRUE(static_cast<SequencedTaskRunner*>(task_runner_.get())
59 ->RunsTasksInCurrentSequence());
60 }
61
62 // Verify task runner CurrentDefaultHandles are set as expected in the task's
63 // scope.
64 switch (execution_mode_) {
65 case TaskSourceExecutionMode::kJob:
66 case TaskSourceExecutionMode::kParallel:
67 EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
68 EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
69 break;
70 case TaskSourceExecutionMode::kSequenced:
71 EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
72 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
73 EXPECT_EQ(task_runner_, SequencedTaskRunner::GetCurrentDefault());
74 break;
75 case TaskSourceExecutionMode::kSingleThread:
76 // SequencedTaskRunner::CurrentDefaultHandle inherits from
77 // SingleThreadTaskRunner::CurrentDefaultHandle so both are expected to be
78 // "set" in the kSingleThread case.
79 EXPECT_TRUE(SingleThreadTaskRunner::HasCurrentDefault());
80 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
81 EXPECT_EQ(task_runner_, SingleThreadTaskRunner::GetCurrentDefault());
82 EXPECT_EQ(task_runner_, SequencedTaskRunner::GetCurrentDefault());
83 break;
84 }
85
86 {
87 AutoLock auto_lock(lock_);
88
89 DCHECK_LE(task_index, num_posted_tasks_);
90
91 if ((execution_mode_ == TaskSourceExecutionMode::kSingleThread ||
92 execution_mode_ == TaskSourceExecutionMode::kSequenced) &&
93 task_index != ran_tasks_.size()) {
94 ADD_FAILURE() << "A task didn't run in the expected order.";
95 }
96
97 if (execution_mode_ == TaskSourceExecutionMode::kSingleThread)
98 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
99
100 if (ran_tasks_.find(task_index) != ran_tasks_.end())
101 ADD_FAILURE() << "A task ran more than once.";
102 ran_tasks_.insert(task_index);
103
104 cv_.Signal();
105 }
106
107 if (!after_task_closure.is_null())
108 std::move(after_task_closure).Run();
109 }
110
111 } // namespace test
112 } // namespace internal
113 } // namespace base
114