1 // Copyright 2020 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/bind_post_task.h"
6
7 #include "base/functional/bind.h"
8 #include "base/functional/callback.h"
9 #include "base/memory/raw_ref.h"
10 #include "base/sequence_checker_impl.h"
11 #include "base/task/sequenced_task_runner.h"
12 #include "base/test/task_environment.h"
13 #include "base/threading/thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17 namespace {
18
SetBool(bool * variable,bool value)19 void SetBool(bool* variable, bool value) {
20 *variable = value;
21 }
22
SetInt(int * variable,int value)23 void SetInt(int* variable, int value) {
24 *variable = value;
25 }
26
SetIntFromUniquePtr(int * variable,std::unique_ptr<int> value)27 void SetIntFromUniquePtr(int* variable, std::unique_ptr<int> value) {
28 *variable = *value;
29 }
30
Multiply(int value)31 int Multiply(int value) {
32 return value * 5;
33 }
34
ClearReference(OnceClosure callback)35 void ClearReference(OnceClosure callback) {}
36
37 class SequenceRestrictionChecker {
38 public:
SequenceRestrictionChecker(bool & set_on_destroy)39 explicit SequenceRestrictionChecker(bool& set_on_destroy)
40 : set_on_destroy_(set_on_destroy) {}
41
~SequenceRestrictionChecker()42 ~SequenceRestrictionChecker() {
43 EXPECT_TRUE(checker_.CalledOnValidSequence());
44 *set_on_destroy_ = true;
45 }
46
Run()47 void Run() { EXPECT_TRUE(checker_.CalledOnValidSequence()); }
48
49 private:
50 SequenceCheckerImpl checker_;
51 const raw_ref<bool> set_on_destroy_;
52 };
53
54 } // namespace
55
56 class BindPostTaskTest : public testing::Test {
57 protected:
58 test::SingleThreadTaskEnvironment task_environment_;
59 scoped_refptr<SequencedTaskRunner> task_runner_ =
60 SequencedTaskRunner::GetCurrentDefault();
61 };
62
TEST_F(BindPostTaskTest,OnceClosure)63 TEST_F(BindPostTaskTest, OnceClosure) {
64 bool val = false;
65 OnceClosure cb = BindOnce(&SetBool, &val, true);
66 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
67
68 std::move(post_cb).Run();
69 EXPECT_FALSE(val);
70
71 RunLoop().RunUntilIdle();
72 EXPECT_TRUE(val);
73 }
74
TEST_F(BindPostTaskTest,OnceCallback)75 TEST_F(BindPostTaskTest, OnceCallback) {
76 OnceCallback<void(bool*, bool)> cb = BindOnce(&SetBool);
77 OnceCallback<void(bool*, bool)> post_cb =
78 BindPostTask(task_runner_, std::move(cb));
79
80 bool val = false;
81 std::move(post_cb).Run(&val, true);
82 EXPECT_FALSE(val);
83
84 RunLoop().RunUntilIdle();
85 EXPECT_TRUE(val);
86 }
87
TEST_F(BindPostTaskTest,OnceWithBoundMoveOnlyArg)88 TEST_F(BindPostTaskTest, OnceWithBoundMoveOnlyArg) {
89 int val = 0;
90 OnceClosure cb =
91 BindOnce(&SetIntFromUniquePtr, &val, std::make_unique<int>(10));
92 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
93
94 std::move(post_cb).Run();
95 EXPECT_EQ(val, 0);
96
97 RunLoop().RunUntilIdle();
98 EXPECT_EQ(val, 10);
99 }
100
TEST_F(BindPostTaskTest,OnceWithUnboundMoveOnlyArg)101 TEST_F(BindPostTaskTest, OnceWithUnboundMoveOnlyArg) {
102 int val = 0;
103 OnceCallback<void(std::unique_ptr<int>)> cb =
104 BindOnce(&SetIntFromUniquePtr, &val);
105 OnceCallback<void(std::unique_ptr<int>)> post_cb =
106 BindPostTask(task_runner_, std::move(cb));
107
108 std::move(post_cb).Run(std::make_unique<int>(10));
109 EXPECT_EQ(val, 0);
110
111 RunLoop().RunUntilIdle();
112 EXPECT_EQ(val, 10);
113 }
114
TEST_F(BindPostTaskTest,OnceWithIgnoreResult)115 TEST_F(BindPostTaskTest, OnceWithIgnoreResult) {
116 OnceCallback<void(int)> post_cb =
117 BindPostTask(task_runner_, BindOnce(IgnoreResult(&Multiply)));
118 std::move(post_cb).Run(1);
119 RunLoop().RunUntilIdle();
120 }
121
TEST_F(BindPostTaskTest,OnceThen)122 TEST_F(BindPostTaskTest, OnceThen) {
123 int value = 0;
124
125 // Multiply() returns an int and SetInt() takes an int as a parameter.
126 OnceClosure then_cb =
127 BindOnce(&Multiply, 5)
128 .Then(BindPostTask(task_runner_, BindOnce(&SetInt, &value)));
129
130 std::move(then_cb).Run();
131 EXPECT_EQ(value, 0);
132 RunLoop().RunUntilIdle();
133 EXPECT_EQ(value, 25);
134 }
135
136 // Ensure that the input callback is run/destroyed on the correct thread even if
137 // the callback returned from BindPostTask() is run on a different thread.
TEST_F(BindPostTaskTest,OnceRunDestroyedOnBound)138 TEST_F(BindPostTaskTest, OnceRunDestroyedOnBound) {
139 Thread target_thread("testing");
140 ASSERT_TRUE(target_thread.Start());
141
142 // SequenceRestrictionChecker checks it's creation, Run() and deletion all
143 // happen on the main thread.
144 bool destroyed = false;
145 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
146
147 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is run
148 // on a different thread which triggers a PostTask() back to the test main
149 // thread to invoke `cb` which runs SequenceRestrictionChecker::Run(). After
150 // `cb` has been invoked `checker` is destroyed along with the BindState.
151 OnceClosure cb =
152 BindOnce(&SequenceRestrictionChecker::Run, std::move(checker));
153 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
154 target_thread.task_runner()->PostTask(FROM_HERE, std::move(post_cb));
155
156 target_thread.FlushForTesting();
157 EXPECT_FALSE(destroyed);
158 RunLoop().RunUntilIdle();
159 EXPECT_TRUE(destroyed);
160 }
161
162 // Ensure that the input callback is destroyed on the correct thread even if the
163 // callback returned from BindPostTask() is destroyed without being run on a
164 // different thread.
TEST_F(BindPostTaskTest,OnceNotRunDestroyedOnBound)165 TEST_F(BindPostTaskTest, OnceNotRunDestroyedOnBound) {
166 Thread target_thread("testing");
167 ASSERT_TRUE(target_thread.Start());
168
169 // SequenceRestrictionChecker checks it's creation and deletion all happen on
170 // the test main thread.
171 bool destroyed = false;
172 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
173
174 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is
175 // deleted on a different thread which triggers a PostTask() back to the test
176 // main thread to destroy `cb` and `checker`.
177 OnceClosure cb =
178 BindOnce(&SequenceRestrictionChecker::Run, std::move(checker));
179 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
180 target_thread.task_runner()->PostTask(
181 FROM_HERE, BindOnce(&ClearReference, std::move(post_cb)));
182
183 target_thread.FlushForTesting();
184 EXPECT_FALSE(destroyed);
185 RunLoop().RunUntilIdle();
186 EXPECT_TRUE(destroyed);
187 }
188
TEST_F(BindPostTaskTest,RepeatingClosure)189 TEST_F(BindPostTaskTest, RepeatingClosure) {
190 bool val = false;
191 RepeatingClosure cb = BindRepeating(&SetBool, &val, true);
192 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
193
194 post_cb.Run();
195 EXPECT_FALSE(val);
196
197 RunLoop().RunUntilIdle();
198 EXPECT_TRUE(val);
199
200 val = false;
201 post_cb.Run();
202 EXPECT_FALSE(val);
203
204 RunLoop().RunUntilIdle();
205 EXPECT_TRUE(val);
206 }
207
TEST_F(BindPostTaskTest,RepeatingCallback)208 TEST_F(BindPostTaskTest, RepeatingCallback) {
209 RepeatingCallback<void(bool*, bool)> cb = BindRepeating(&SetBool);
210 RepeatingCallback<void(bool*, bool)> post_cb =
211 BindPostTask(task_runner_, std::move(cb));
212
213 bool val = false;
214 post_cb.Run(&val, true);
215 EXPECT_FALSE(val);
216
217 RunLoop().RunUntilIdle();
218 EXPECT_TRUE(val);
219
220 post_cb.Run(&val, false);
221 EXPECT_TRUE(val);
222
223 RunLoop().RunUntilIdle();
224 EXPECT_FALSE(val);
225 }
226
TEST_F(BindPostTaskTest,RepeatingWithUnboundMoveOnlyArg)227 TEST_F(BindPostTaskTest, RepeatingWithUnboundMoveOnlyArg) {
228 int val = 0;
229 RepeatingCallback<void(std::unique_ptr<int>)> cb =
230 BindRepeating(&SetIntFromUniquePtr, &val);
231 RepeatingCallback<void(std::unique_ptr<int>)> post_cb =
232 BindPostTask(task_runner_, std::move(cb));
233
234 post_cb.Run(std::make_unique<int>(10));
235 EXPECT_EQ(val, 0);
236
237 RunLoop().RunUntilIdle();
238 EXPECT_EQ(val, 10);
239
240 post_cb.Run(std::make_unique<int>(20));
241 EXPECT_EQ(val, 10);
242
243 RunLoop().RunUntilIdle();
244 EXPECT_EQ(val, 20);
245 }
246
TEST_F(BindPostTaskTest,RepeatingWithIgnoreResult)247 TEST_F(BindPostTaskTest, RepeatingWithIgnoreResult) {
248 RepeatingCallback<void(int)> post_cb =
249 BindPostTask(task_runner_, BindRepeating(IgnoreResult(&Multiply)));
250 std::move(post_cb).Run(1);
251 RunLoop().RunUntilIdle();
252 }
253
TEST_F(BindPostTaskTest,RepeatingThen)254 TEST_F(BindPostTaskTest, RepeatingThen) {
255 int value = 0;
256
257 // Multiply() returns an int and SetInt() takes an int as a parameter.
258 RepeatingCallback<void(int)> then_cb = BindRepeating(&Multiply).Then(
259 BindPostTask(task_runner_, BindRepeating(&SetInt, &value)));
260
261 then_cb.Run(5);
262 EXPECT_EQ(value, 0);
263 RunLoop().RunUntilIdle();
264 EXPECT_EQ(value, 25);
265
266 then_cb.Run(10);
267 EXPECT_EQ(value, 25);
268 RunLoop().RunUntilIdle();
269 EXPECT_EQ(value, 50);
270 }
271
272 // Ensure that the input callback is run/destroyed on the correct thread even if
273 // the callback returned from BindPostTask() is run on a different thread.
TEST_F(BindPostTaskTest,RepeatingRunDestroyedOnBound)274 TEST_F(BindPostTaskTest, RepeatingRunDestroyedOnBound) {
275 Thread target_thread("testing");
276 ASSERT_TRUE(target_thread.Start());
277
278 // SequenceRestrictionChecker checks it's creation, Run() and deletion all
279 // happen on the main thread.
280 bool destroyed = false;
281 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
282
283 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is run
284 // on a different thread which triggers a PostTask() back to the test main
285 // thread to invoke `cb` which runs SequenceRestrictionChecker::Run(). After
286 // `cb` has been invoked `checker` is destroyed along with the BindState.
287 RepeatingClosure cb =
288 BindRepeating(&SequenceRestrictionChecker::Run, std::move(checker));
289 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
290 target_thread.task_runner()->PostTask(FROM_HERE, std::move(post_cb));
291
292 target_thread.FlushForTesting();
293 EXPECT_FALSE(destroyed);
294 RunLoop().RunUntilIdle();
295 EXPECT_TRUE(destroyed);
296 }
297
298 // Ensure that the input callback is destroyed on the correct thread even if the
299 // callback returned from BindPostTask() is destroyed without being run on a
300 // different thread.
TEST_F(BindPostTaskTest,RepeatingNotRunDestroyedOnBound)301 TEST_F(BindPostTaskTest, RepeatingNotRunDestroyedOnBound) {
302 Thread target_thread("testing");
303 ASSERT_TRUE(target_thread.Start());
304
305 // SequenceRestrictionChecker checks it's creation and deletion all happen on
306 // the test main thread.
307 bool destroyed = false;
308 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
309
310 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is
311 // deleted on a different thread which triggers a PostTask() back to the test
312 // main thread to destroy `cb` and `checker`.
313 RepeatingClosure cb =
314 BindRepeating(&SequenceRestrictionChecker::Run, std::move(checker));
315 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
316 target_thread.task_runner()->PostTask(
317 FROM_HERE, BindRepeating(&ClearReference, std::move(post_cb)));
318
319 target_thread.FlushForTesting();
320 EXPECT_FALSE(destroyed);
321 RunLoop().RunUntilIdle();
322 EXPECT_TRUE(destroyed);
323 }
324
325 } // namespace base
326