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/sequenced_task_runner.h"
6
7 #include <utility>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/gtest_prod_util.h"
13 #include "base/location.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/run_loop.h"
17 #include "base/sequence_checker_impl.h"
18 #include "base/task/sequenced_task_runner.h"
19 #include "base/task/thread_pool.h"
20 #include "base/test/bind.h"
21 #include "base/test/gtest_util.h"
22 #include "base/test/null_task_runner.h"
23 #include "base/test/task_environment.h"
24 #include "base/test/test_mock_time_task_runner.h"
25 #include "base/test/test_simple_task_runner.h"
26 #include "base/threading/thread.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace base {
30 namespace {
31
32 class FlagOnDelete {
33 public:
FlagOnDelete(bool * deleted,scoped_refptr<SequencedTaskRunner> expected_deletion_sequence)34 FlagOnDelete(bool* deleted,
35 scoped_refptr<SequencedTaskRunner> expected_deletion_sequence)
36 : deleted_(deleted),
37 expected_deletion_sequence_(std::move(expected_deletion_sequence)) {}
38 FlagOnDelete(const FlagOnDelete&) = delete;
39 FlagOnDelete& operator=(const FlagOnDelete&) = delete;
40
~FlagOnDelete()41 ~FlagOnDelete() {
42 EXPECT_FALSE(*deleted_);
43 *deleted_ = true;
44 if (expected_deletion_sequence_)
45 EXPECT_TRUE(expected_deletion_sequence_->RunsTasksInCurrentSequence());
46 }
47
48 private:
49 raw_ptr<bool> deleted_;
50 const scoped_refptr<SequencedTaskRunner> expected_deletion_sequence_;
51 };
52
53 class SequencedTaskRunnerTest : public testing::Test {
54 public:
55 SequencedTaskRunnerTest(const SequencedTaskRunnerTest&) = delete;
56 SequencedTaskRunnerTest& operator=(const SequencedTaskRunnerTest&) = delete;
57
58 protected:
SequencedTaskRunnerTest()59 SequencedTaskRunnerTest() : foreign_thread_("foreign") {}
60
SetUp()61 void SetUp() override {
62 foreign_thread_.Start();
63 foreign_runner_ = foreign_thread_.task_runner();
64 }
65
66 scoped_refptr<SequencedTaskRunner> foreign_runner_;
67
68 Thread foreign_thread_;
69
70 private:
71 test::TaskEnvironment task_environment_;
72 };
73
74 } // namespace
75
76 using SequenceBoundUniquePtr =
77 std::unique_ptr<FlagOnDelete, OnTaskRunnerDeleter>;
78
TEST_F(SequencedTaskRunnerTest,OnTaskRunnerDeleterOnMainThread)79 TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterOnMainThread) {
80 bool deleted_on_main_thread = false;
81 SequenceBoundUniquePtr ptr(
82 new FlagOnDelete(&deleted_on_main_thread,
83 SequencedTaskRunner::GetCurrentDefault()),
84 OnTaskRunnerDeleter(SequencedTaskRunner::GetCurrentDefault()));
85 EXPECT_FALSE(deleted_on_main_thread);
86 foreign_runner_->PostTask(FROM_HERE, DoNothingWithBoundArgs(std::move(ptr)));
87
88 {
89 RunLoop run_loop;
90 foreign_runner_->PostTaskAndReply(FROM_HERE, BindOnce([] {}),
91 run_loop.QuitClosure());
92 run_loop.Run();
93 }
94 EXPECT_TRUE(deleted_on_main_thread);
95 }
96
TEST_F(SequencedTaskRunnerTest,OnTaskRunnerDeleterTargetStoppedEarly)97 TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterTargetStoppedEarly) {
98 bool deleted_on_main_thread = false;
99 FlagOnDelete* raw = new FlagOnDelete(
100 &deleted_on_main_thread, SequencedTaskRunner::GetCurrentDefault());
101 SequenceBoundUniquePtr ptr(raw, OnTaskRunnerDeleter(foreign_runner_));
102 EXPECT_FALSE(deleted_on_main_thread);
103
104 // Stopping the target ahead of deleting |ptr| should make its
105 // OnTaskRunnerDeleter no-op.
106 foreign_thread_.Stop();
107 ptr = nullptr;
108 EXPECT_FALSE(deleted_on_main_thread);
109
110 delete raw;
111 EXPECT_TRUE(deleted_on_main_thread);
112 }
113
TEST_F(SequencedTaskRunnerTest,DelayedTaskHandle_RunTask)114 TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_RunTask) {
115 auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
116
117 bool task_ran = false;
118 DelayedTaskHandle delayed_task_handle =
119 task_runner->PostCancelableDelayedTask(
120 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
121 BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
122 EXPECT_TRUE(delayed_task_handle.IsValid());
123 EXPECT_TRUE(task_runner->HasPendingTask());
124
125 // Run the delayed task.
126 task_runner->FastForwardUntilNoTasksRemain();
127
128 EXPECT_FALSE(delayed_task_handle.IsValid());
129 EXPECT_FALSE(task_runner->HasPendingTask());
130 EXPECT_TRUE(task_ran);
131 }
132
TEST_F(SequencedTaskRunnerTest,DelayedTaskHandle_CancelTask)133 TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_CancelTask) {
134 auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
135
136 bool task_ran = false;
137 DelayedTaskHandle delayed_task_handle =
138 task_runner->PostCancelableDelayedTask(
139 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
140 BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
141 EXPECT_TRUE(delayed_task_handle.IsValid());
142 EXPECT_TRUE(task_runner->HasPendingTask());
143
144 // Cancel the delayed task.
145 delayed_task_handle.CancelTask();
146
147 EXPECT_FALSE(delayed_task_handle.IsValid());
148 EXPECT_FALSE(task_runner->HasPendingTask());
149 EXPECT_FALSE(task_ran);
150 }
151
TEST_F(SequencedTaskRunnerTest,DelayedTaskHandle_DestroyTask)152 TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_DestroyTask) {
153 auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
154
155 bool task_ran = false;
156 DelayedTaskHandle delayed_task_handle =
157 task_runner->PostCancelableDelayedTask(
158 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
159 BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
160 EXPECT_TRUE(delayed_task_handle.IsValid());
161 EXPECT_TRUE(task_runner->HasPendingTask());
162
163 // Destroy the pending task.
164 task_runner->ClearPendingTasks();
165
166 EXPECT_FALSE(delayed_task_handle.IsValid());
167 EXPECT_FALSE(task_runner->HasPendingTask());
168 EXPECT_FALSE(task_ran);
169 }
170
171 // Tests that if PostCancelableDelayedTask() fails, the returned handle will be
172 // invalid.
TEST_F(SequencedTaskRunnerTest,DelayedTaskHandle_PostTaskFailed)173 TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_PostTaskFailed) {
174 auto task_runner = MakeRefCounted<NullTaskRunner>();
175
176 bool task_ran = false;
177 DelayedTaskHandle delayed_task_handle =
178 task_runner->PostCancelableDelayedTask(
179 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
180 BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
181 EXPECT_FALSE(delayed_task_handle.IsValid());
182 EXPECT_FALSE(task_ran);
183 }
184
185 namespace {
186
187 // Tests for the SequencedTaskRunner::CurrentDefaultHandle machinery.
188 class SequencedTaskRunnerCurrentDefaultHandleTest : public ::testing::Test {
189 protected:
190 // Verifies that the context it runs on has a
191 // SequencedTaskRunner::CurrentDefaultHandle and that posting to it results in
192 // the posted task running in that same context (sequence).
VerifyCurrentSequencedTaskRunner()193 static void VerifyCurrentSequencedTaskRunner() {
194 ASSERT_TRUE(SequencedTaskRunner::HasCurrentDefault());
195 scoped_refptr<SequencedTaskRunner> task_runner =
196 SequencedTaskRunner::GetCurrentDefault();
197 ASSERT_TRUE(task_runner);
198
199 // Use SequenceCheckerImpl to make sure it's not a no-op in Release builds.
200 std::unique_ptr<SequenceCheckerImpl> sequence_checker =
201 std::make_unique<SequenceCheckerImpl>();
202 task_runner->PostTask(
203 FROM_HERE,
204 base::BindOnce(
205 &SequencedTaskRunnerCurrentDefaultHandleTest::CheckValidSequence,
206 std::move(sequence_checker)));
207 }
208
CheckValidSequence(std::unique_ptr<SequenceCheckerImpl> sequence_checker)209 static void CheckValidSequence(
210 std::unique_ptr<SequenceCheckerImpl> sequence_checker) {
211 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
212 }
213
214 test::TaskEnvironment task_environment_;
215 };
216
217 } // namespace
218
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,FromTaskEnvironment)219 TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest, FromTaskEnvironment) {
220 VerifyCurrentSequencedTaskRunner();
221 RunLoop().RunUntilIdle();
222 }
223
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,FromThreadPoolSequencedTask)224 TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,
225 FromThreadPoolSequencedTask) {
226 base::ThreadPool::CreateSequencedTaskRunner({})->PostTask(
227 FROM_HERE, base::BindOnce(&SequencedTaskRunnerCurrentDefaultHandleTest::
228 VerifyCurrentSequencedTaskRunner));
229 task_environment_.RunUntilIdle();
230 }
231
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,NoHandleFromUnsequencedTask)232 TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,
233 NoHandleFromUnsequencedTask) {
234 base::ThreadPool::PostTask(base::BindOnce(
235 []() { EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault()); }));
236 task_environment_.RunUntilIdle();
237 }
238
239 // Verify that `CurrentDefaultHandle` can be used to set the current default
240 // `SequencedTaskRunner` to null in a scope that already has a default.
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,OverrideWithNull)241 TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest, OverrideWithNull) {
242 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
243 auto tr1 = SequencedTaskRunner::GetCurrentDefault();
244 EXPECT_TRUE(tr1);
245
246 {
247 SequencedTaskRunner::CurrentDefaultHandle handle(
248 nullptr, SequencedTaskRunner::CurrentDefaultHandle::MayAlreadyExist{});
249 EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
250 EXPECT_CHECK_DEATH(
251 { auto tr2 = SequencedTaskRunner::GetCurrentDefault(); });
252 }
253
254 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
255 EXPECT_EQ(tr1, SequencedTaskRunner::GetCurrentDefault());
256 }
257
258 // Verify that `CurrentDefaultHandle` can be used to set the current default
259 // `SequencedTaskRunner` to a non-null value in a scope that already has a
260 // default.
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,OverrideWithNonNull)261 TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest, OverrideWithNonNull) {
262 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
263 auto tr1 = SequencedTaskRunner::GetCurrentDefault();
264 EXPECT_TRUE(tr1);
265
266 {
267 auto tr2 = MakeRefCounted<TestSimpleTaskRunner>();
268 SequencedTaskRunner::CurrentDefaultHandle handle(
269 tr2, SequencedTaskRunner::CurrentDefaultHandle::MayAlreadyExist{});
270 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
271 EXPECT_EQ(tr2, SequencedTaskRunner::GetCurrentDefault());
272 }
273
274 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
275 EXPECT_EQ(tr1, SequencedTaskRunner::GetCurrentDefault());
276 }
277
TEST(SequencedTaskRunnerCurrentDefaultHandleTestWithoutTaskEnvironment,FromHandleInScope)278 TEST(SequencedTaskRunnerCurrentDefaultHandleTestWithoutTaskEnvironment,
279 FromHandleInScope) {
280 scoped_refptr<SequencedTaskRunner> test_task_runner =
281 MakeRefCounted<TestSimpleTaskRunner>();
282 EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
283 EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
284 {
285 SequencedTaskRunner::CurrentDefaultHandle current_default(test_task_runner);
286 EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
287 EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
288 EXPECT_EQ(test_task_runner, SequencedTaskRunner::GetCurrentDefault());
289 }
290 EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
291 EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
292 }
293
294 } // namespace base
295