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