1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task_scheduler/test_task_factory.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/sequenced_task_runner_handle.h"
14 #include "base/threading/thread_task_runner_handle.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,ExecutionMode execution_mode)21 TestTaskFactory::TestTaskFactory(scoped_refptr<TaskRunner> task_runner,
22 ExecutionMode 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, Closure());
55
56 EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
57
58 // Verify TaskRunnerHandles are set as expected in the task's scope.
59 switch (execution_mode_) {
60 case ExecutionMode::PARALLEL:
61 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
62 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
63 break;
64 case ExecutionMode::SEQUENCED:
65 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
66 EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet());
67 EXPECT_EQ(task_runner_, SequencedTaskRunnerHandle::Get());
68 break;
69 case ExecutionMode::SINGLE_THREADED:
70 // SequencedTaskRunnerHandle inherits from ThreadTaskRunnerHandle so
71 // both are expected to be "set" in the SINGLE_THREADED case.
72 EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
73 EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet());
74 EXPECT_EQ(task_runner_, ThreadTaskRunnerHandle::Get());
75 EXPECT_EQ(task_runner_, SequencedTaskRunnerHandle::Get());
76 break;
77 }
78
79 {
80 AutoLock auto_lock(lock_);
81
82 DCHECK_LE(task_index, num_posted_tasks_);
83
84 if ((execution_mode_ == ExecutionMode::SINGLE_THREADED ||
85 execution_mode_ == ExecutionMode::SEQUENCED) &&
86 task_index != ran_tasks_.size()) {
87 ADD_FAILURE() << "A task didn't run in the expected order.";
88 }
89
90 if (execution_mode_ == ExecutionMode::SINGLE_THREADED)
91 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
92
93 if (ran_tasks_.find(task_index) != ran_tasks_.end())
94 ADD_FAILURE() << "A task ran more than once.";
95 ran_tasks_.insert(task_index);
96
97 cv_.Signal();
98 }
99
100 if (!after_task_closure.is_null())
101 std::move(after_task_closure).Run();
102 }
103
104 } // namespace test
105 } // namespace internal
106 } // namespace base
107