1 // Copyright 2015 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 "third_party/blink/renderer/platform/scheduler/worker/worker_thread.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/macros.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/task/task_executor.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
15 #include "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h"
16 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
17 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
18
19 using testing::_;
20 using testing::AnyOf;
21 using testing::ElementsAre;
22 using testing::Invoke;
23
24 namespace blink {
25 namespace scheduler {
26 namespace worker_thread_unittest {
27
28 class MockTask {
29 public:
30 MOCK_METHOD0(Run, void());
31 };
32
33 class MockIdleTask {
34 public:
35 MOCK_METHOD1(Run, void(double deadline));
36 };
37
38 class TestObserver : public Thread::TaskObserver {
39 public:
TestObserver(StringBuilder * calls)40 explicit TestObserver(StringBuilder* calls) : calls_(calls) {}
41
42 ~TestObserver() override = default;
43
WillProcessTask(const base::PendingTask &,bool)44 void WillProcessTask(const base::PendingTask&, bool) override {
45 calls_->Append(" willProcessTask");
46 }
47
DidProcessTask(const base::PendingTask &)48 void DidProcessTask(const base::PendingTask&) override {
49 calls_->Append(" didProcessTask");
50 }
51
52 private:
53 StringBuilder* calls_; // NOT OWNED
54 };
55
RunTestTask(StringBuilder * calls)56 void RunTestTask(StringBuilder* calls) {
57 calls->Append(" run");
58 }
59
AddTaskObserver(Thread * thread,TestObserver * observer)60 void AddTaskObserver(Thread* thread, TestObserver* observer) {
61 thread->AddTaskObserver(observer);
62 }
63
RemoveTaskObserver(Thread * thread,TestObserver * observer)64 void RemoveTaskObserver(Thread* thread, TestObserver* observer) {
65 thread->RemoveTaskObserver(observer);
66 }
67
ShutdownOnThread(Thread * thread)68 void ShutdownOnThread(Thread* thread) {
69 thread->Scheduler()->Shutdown();
70 }
71
72 class WorkerThreadTest : public testing::Test {
73 public:
74 WorkerThreadTest() = default;
75
76 ~WorkerThreadTest() override = default;
77
SetUp()78 void SetUp() override {
79 thread_ =
80 Thread::CreateThread(ThreadCreationParams(ThreadType::kTestThread));
81 }
82
RunOnWorkerThread(const base::Location & from_here,base::OnceClosure task)83 void RunOnWorkerThread(const base::Location& from_here,
84 base::OnceClosure task) {
85 base::WaitableEvent completion(
86 base::WaitableEvent::ResetPolicy::AUTOMATIC,
87 base::WaitableEvent::InitialState::NOT_SIGNALED);
88 thread_->GetTaskRunner()->PostTask(
89 from_here,
90 base::BindOnce(&WorkerThreadTest::RunOnWorkerThreadTask,
91 base::Unretained(this), std::move(task), &completion));
92 completion.Wait();
93 }
94
95 protected:
RunOnWorkerThreadTask(base::OnceClosure task,base::WaitableEvent * completion)96 void RunOnWorkerThreadTask(base::OnceClosure task,
97 base::WaitableEvent* completion) {
98 std::move(task).Run();
99 completion->Signal();
100 }
101
102 std::unique_ptr<Thread> thread_;
103
104 DISALLOW_COPY_AND_ASSIGN(WorkerThreadTest);
105 };
106
TEST_F(WorkerThreadTest,TestDefaultTask)107 TEST_F(WorkerThreadTest, TestDefaultTask) {
108 MockTask task;
109 base::WaitableEvent completion(
110 base::WaitableEvent::ResetPolicy::AUTOMATIC,
111 base::WaitableEvent::InitialState::NOT_SIGNALED);
112
113 EXPECT_CALL(task, Run());
114 ON_CALL(task, Run()).WillByDefault(Invoke([&completion]() {
115 completion.Signal();
116 }));
117
118 PostCrossThreadTask(
119 *thread_->GetTaskRunner(), FROM_HERE,
120 CrossThreadBindOnce(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
121 completion.Wait();
122 }
123
TEST_F(WorkerThreadTest,TestTaskObserver)124 TEST_F(WorkerThreadTest, TestTaskObserver) {
125 StringBuilder calls;
126 TestObserver observer(&calls);
127
128 RunOnWorkerThread(FROM_HERE,
129 base::BindOnce(&AddTaskObserver, thread_.get(), &observer));
130 PostCrossThreadTask(
131 *thread_->GetTaskRunner(), FROM_HERE,
132 CrossThreadBindOnce(&RunTestTask, WTF::CrossThreadUnretained(&calls)));
133 RunOnWorkerThread(
134 FROM_HERE, base::BindOnce(&RemoveTaskObserver, thread_.get(), &observer));
135
136 // We need to be careful what we test here. We want to make sure the
137 // observers are un in the expected order before and after the task.
138 // Sometimes we get an internal scheduler task running before or after
139 // TestTask as well. This is not a bug, and we need to make sure the test
140 // doesn't fail when that happens.
141 EXPECT_THAT(calls.ToString().Utf8(),
142 testing::HasSubstr("willProcessTask run didProcessTask"));
143 }
144
TEST_F(WorkerThreadTest,TestShutdown)145 TEST_F(WorkerThreadTest, TestShutdown) {
146 MockTask task;
147 MockTask delayed_task;
148
149 EXPECT_CALL(task, Run()).Times(0);
150 EXPECT_CALL(delayed_task, Run()).Times(0);
151
152 RunOnWorkerThread(FROM_HERE,
153 base::BindOnce(&ShutdownOnThread, thread_.get()));
154 PostCrossThreadTask(
155 *thread_->GetTaskRunner(), FROM_HERE,
156 CrossThreadBindOnce(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
157 PostDelayedCrossThreadTask(
158 *thread_->GetTaskRunner(), FROM_HERE,
159 CrossThreadBindOnce(&MockTask::Run,
160 WTF::CrossThreadUnretained(&delayed_task)),
161 base::TimeDelta::FromMilliseconds(50));
162 thread_.reset();
163 }
164
TEST_F(WorkerThreadTest,GetTaskExecutorForCurrentThreadInPostedTask)165 TEST_F(WorkerThreadTest, GetTaskExecutorForCurrentThreadInPostedTask) {
166 RunOnWorkerThread(FROM_HERE, base::BindOnce([]() {
167 EXPECT_THAT(base::GetTaskExecutorForCurrentThread(),
168 testing::NotNull());
169 }));
170 }
171
172 } // namespace worker_thread_unittest
173 } // namespace scheduler
174 } // namespace blink
175