xref: /aosp_15_r20/external/cronet/base/task/bind_post_task_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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