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