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/thread_pool/sequence.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/test/gtest_util.h"
13 #include "base/time/time.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18 namespace internal {
19
20 namespace {
21
22 class MockTask {
23 public:
24 MOCK_METHOD0(Run, void());
25 };
26
CreateTask(MockTask * mock_task)27 Task CreateTask(MockTask* mock_task) {
28 return Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(mock_task)),
29 TimeDelta());
30 }
31
ExpectMockTask(MockTask * mock_task,Task * task)32 void ExpectMockTask(MockTask* mock_task, Task* task) {
33 EXPECT_CALL(*mock_task, Run());
34 std::move(task->task).Run();
35 testing::Mock::VerifyAndClear(mock_task);
36 }
37
38 } // namespace
39
TEST(ThreadPoolSequenceTest,PushTakeRemove)40 TEST(ThreadPoolSequenceTest, PushTakeRemove) {
41 testing::StrictMock<MockTask> mock_task_a;
42 testing::StrictMock<MockTask> mock_task_b;
43 testing::StrictMock<MockTask> mock_task_c;
44 testing::StrictMock<MockTask> mock_task_d;
45 testing::StrictMock<MockTask> mock_task_e;
46
47 scoped_refptr<Sequence> sequence =
48 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
49 TaskSourceExecutionMode::kParallel);
50 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
51
52 // Push task A in the sequence. PushTask() should return true since it's the
53 // first task->
54 EXPECT_TRUE(sequence_transaction.WillPushTask());
55 sequence_transaction.PushTask(CreateTask(&mock_task_a));
56
57 // Push task B, C and D in the sequence. PushTask() should return false
58 // since there is already a task in a sequence.
59 EXPECT_FALSE(sequence_transaction.WillPushTask());
60 sequence_transaction.PushTask(CreateTask(&mock_task_b));
61 EXPECT_FALSE(sequence_transaction.WillPushTask());
62 sequence_transaction.PushTask(CreateTask(&mock_task_c));
63 EXPECT_FALSE(sequence_transaction.WillPushTask());
64 sequence_transaction.PushTask(CreateTask(&mock_task_d));
65
66 // Take the task in front of the sequence. It should be task A.
67 auto registered_task_source =
68 RegisteredTaskSource::CreateForTesting(sequence);
69 registered_task_source.WillRunTask();
70 Optional<Task> task = registered_task_source.TakeTask(&sequence_transaction);
71 ExpectMockTask(&mock_task_a, &task.value());
72 EXPECT_FALSE(task->queue_time.is_null());
73
74 // Remove the empty slot. Task B should now be in front.
75 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
76
77 EXPECT_FALSE(sequence_transaction.WillPushTask());
78 registered_task_source.WillRunTask();
79 task = registered_task_source.TakeTask(&sequence_transaction);
80 ExpectMockTask(&mock_task_b, &task.value());
81 EXPECT_FALSE(task->queue_time.is_null());
82
83 // Remove the empty slot. Task C should now be in front.
84 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
85
86 EXPECT_FALSE(sequence_transaction.WillPushTask());
87 registered_task_source.WillRunTask();
88 task = registered_task_source.TakeTask(&sequence_transaction);
89 ExpectMockTask(&mock_task_c, &task.value());
90 EXPECT_FALSE(task->queue_time.is_null());
91
92 // Remove the empty slot.
93 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
94
95 // Push task E in the sequence.
96 EXPECT_FALSE(sequence_transaction.WillPushTask());
97 sequence_transaction.PushTask(CreateTask(&mock_task_e));
98
99 // Task D should be in front.
100 registered_task_source.WillRunTask();
101 task = registered_task_source.TakeTask(&sequence_transaction);
102 ExpectMockTask(&mock_task_d, &task.value());
103 EXPECT_FALSE(task->queue_time.is_null());
104
105 // Remove the empty slot. Task E should now be in front.
106 EXPECT_TRUE(registered_task_source.DidProcessTask(&sequence_transaction));
107 EXPECT_FALSE(sequence_transaction.WillPushTask());
108 registered_task_source.WillRunTask();
109 task = registered_task_source.TakeTask(&sequence_transaction);
110 ExpectMockTask(&mock_task_e, &task.value());
111 EXPECT_FALSE(task->queue_time.is_null());
112
113 // Remove the empty slot. The sequence should now be empty.
114 EXPECT_FALSE(registered_task_source.DidProcessTask(&sequence_transaction));
115 EXPECT_TRUE(sequence_transaction.WillPushTask());
116 }
117
118 // Verifies the sort key of a BEST_EFFORT sequence that contains one task.
TEST(ThreadPoolSequenceTest,GetSortKeyBestEffort)119 TEST(ThreadPoolSequenceTest, GetSortKeyBestEffort) {
120 // Create a BEST_EFFORT sequence with a task.
121 Task best_effort_task(FROM_HERE, DoNothing(), TimeDelta());
122 scoped_refptr<Sequence> best_effort_sequence =
123 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT), nullptr,
124 TaskSourceExecutionMode::kParallel);
125 Sequence::Transaction best_effort_sequence_transaction(
126 best_effort_sequence->BeginTransaction());
127 best_effort_sequence_transaction.PushTask(std::move(best_effort_task));
128
129 // Get the sort key.
130 const TaskSourceSortKey best_effort_sort_key =
131 best_effort_sequence->GetSortKey();
132
133 // Take the task from the sequence, so that its sequenced time is available
134 // for the check below.
135 auto best_effort_registered_task_source =
136 RegisteredTaskSource::CreateForTesting(best_effort_sequence);
137 best_effort_registered_task_source.WillRunTask();
138 auto take_best_effort_task = best_effort_registered_task_source.TakeTask(
139 &best_effort_sequence_transaction);
140
141 // Verify the sort key.
142 EXPECT_EQ(TaskPriority::BEST_EFFORT, best_effort_sort_key.priority());
143 EXPECT_EQ(take_best_effort_task.queue_time,
144 best_effort_sort_key.ready_time());
145
146 // DidProcessTask for correctness.
147 best_effort_registered_task_source.DidProcessTask(
148 &best_effort_sequence_transaction);
149 }
150
151 // Same as ThreadPoolSequenceTest.GetSortKeyBestEffort, but with a
152 // USER_VISIBLE sequence.
TEST(ThreadPoolSequenceTest,GetSortKeyForeground)153 TEST(ThreadPoolSequenceTest, GetSortKeyForeground) {
154 // Create a USER_VISIBLE sequence with a task.
155 Task foreground_task(FROM_HERE, DoNothing(), TimeDelta());
156 scoped_refptr<Sequence> foreground_sequence =
157 MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE), nullptr,
158 TaskSourceExecutionMode::kParallel);
159 Sequence::Transaction foreground_sequence_transaction(
160 foreground_sequence->BeginTransaction());
161 foreground_sequence_transaction.PushTask(std::move(foreground_task));
162
163 // Get the sort key.
164 const TaskSourceSortKey foreground_sort_key =
165 foreground_sequence->GetSortKey();
166
167 // Take the task from the sequence, so that its sequenced time is available
168 // for the check below.
169 auto foreground_registered_task_source =
170 RegisteredTaskSource::CreateForTesting(foreground_sequence);
171 foreground_registered_task_source.WillRunTask();
172 auto take_foreground_task = foreground_registered_task_source.TakeTask(
173 &foreground_sequence_transaction);
174
175 // Verify the sort key.
176 EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority());
177 EXPECT_EQ(take_foreground_task.queue_time, foreground_sort_key.ready_time());
178
179 // DidProcessTask for correctness.
180 foreground_registered_task_source.DidProcessTask(
181 &foreground_sequence_transaction);
182 }
183
184 // Verify that a DCHECK fires if DidProcessTask() is called on a sequence which
185 // didn't return a Task.
TEST(ThreadPoolSequenceTest,DidProcessTaskWithoutWillRunTask)186 TEST(ThreadPoolSequenceTest, DidProcessTaskWithoutWillRunTask) {
187 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
188 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
189 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
190 sequence_transaction.PushTask(Task(FROM_HERE, DoNothing(), TimeDelta()));
191
192 auto registered_task_source =
193 RegisteredTaskSource::CreateForTesting(sequence);
194 EXPECT_DCHECK_DEATH({
195 registered_task_source.DidProcessTask(&sequence_transaction);
196 });
197 }
198
199 // Verify that a DCHECK fires if TakeTask() is called on a sequence whose front
200 // slot is empty.
TEST(ThreadPoolSequenceTest,TakeEmptyFrontSlot)201 TEST(ThreadPoolSequenceTest, TakeEmptyFrontSlot) {
202 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
203 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
204 Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
205 sequence_transaction.PushTask(Task(FROM_HERE, DoNothing(), TimeDelta()));
206
207 auto registered_task_source =
208 RegisteredTaskSource::CreateForTesting(sequence);
209 {
210 registered_task_source.WillRunTask();
211 IgnoreResult(registered_task_source.TakeTask(&sequence_transaction));
212 registered_task_source.DidProcessTask(&sequence_transaction);
213 }
214 EXPECT_DCHECK_DEATH({
215 registered_task_source.WillRunTask();
216 auto task = registered_task_source.TakeTask(&sequence_transaction);
217 });
218 }
219
220 // Verify that a DCHECK fires if TakeTask() is called on an empty sequence.
TEST(ThreadPoolSequenceTest,TakeEmptySequence)221 TEST(ThreadPoolSequenceTest, TakeEmptySequence) {
222 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
223 TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
224 auto registered_task_source =
225 RegisteredTaskSource::CreateForTesting(sequence);
226 EXPECT_DCHECK_DEATH({
227 registered_task_source.WillRunTask();
228 auto task = registered_task_source.TakeTask();
229 });
230 }
231
232 } // namespace internal
233 } // namespace base
234