xref: /aosp_15_r20/external/cronet/base/sequence_checker_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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/sequence_checker.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <string>
11 #include <utility>
12 
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/sequence_checker_impl.h"
16 #include "base/sequence_token.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/task/thread_pool.h"
19 #include "base/test/bind.h"
20 #include "base/test/gtest_util.h"
21 #include "base/test/task_environment.h"
22 #include "base/threading/simple_thread.h"
23 #include "base/threading/thread_local.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace base::internal {
27 
28 namespace {
29 
30 // Runs a callback on another thread.
31 class RunCallbackThread : public SimpleThread {
32  public:
RunCallbackThread(OnceClosure callback)33   explicit RunCallbackThread(OnceClosure callback)
34       : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
35     Start();
36     Join();
37   }
38   RunCallbackThread(const RunCallbackThread&) = delete;
39   RunCallbackThread& operator=(const RunCallbackThread&) = delete;
40 
41  private:
42   // SimpleThread:
Run()43   void Run() override { std::move(callback_).Run(); }
44 
45   OnceClosure callback_;
46 };
47 
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)48 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
49   ASSERT_TRUE(sequence_checker);
50 
51   // This should bind |sequence_checker| to the current sequence if it wasn't
52   // already bound to a sequence.
53   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
54 
55   // Since |sequence_checker| is now bound to the current sequence, another call
56   // to CalledOnValidSequence() should return true.
57   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
58 }
59 
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)60 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
61   ASSERT_TRUE(sequence_checker);
62   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
63 }
64 
65 }  // namespace
66 
TEST(SequenceCheckerTest,NoTaskScope)67 TEST(SequenceCheckerTest, NoTaskScope) {
68   SequenceCheckerImpl sequence_checker;
69   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
70 }
71 
TEST(SequenceCheckerTest,TaskScope)72 TEST(SequenceCheckerTest, TaskScope) {
73   TaskScope task_scope(SequenceToken::Create(),
74                        /* is_thread_bound=*/false);
75   SequenceCheckerImpl sequence_checker;
76   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
77 }
78 
TEST(SequenceCheckerTest,TaskScopeThreadBound)79 TEST(SequenceCheckerTest, TaskScopeThreadBound) {
80   TaskScope task_scope(SequenceToken::Create(),
81                        /* is_thread_bound=*/true);
82   SequenceCheckerImpl sequence_checker;
83   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
84 }
85 
TEST(SequenceCheckerTest,DifferentThreadNoTaskScope)86 TEST(SequenceCheckerTest, DifferentThreadNoTaskScope) {
87   SequenceCheckerImpl sequence_checker;
88   RunCallbackThread thread(
89       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
90 }
91 
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceToken)92 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceToken) {
93   SequenceCheckerImpl sequence_checker;
94   RunCallbackThread thread(BindLambdaForTesting([&]() {
95     TaskScope task_scope(SequenceToken::Create(),
96                          /* is_thread_bound=*/false);
97     ExpectNotCalledOnValidSequence(&sequence_checker);
98   }));
99 }
100 
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceTokenThreadBound)101 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceTokenThreadBound) {
102   SequenceCheckerImpl sequence_checker;
103   RunCallbackThread thread(BindLambdaForTesting([&]() {
104     TaskScope task_scope(SequenceToken::Create(),
105                          /* is_thread_bound=*/true);
106     ExpectNotCalledOnValidSequence(&sequence_checker);
107   }));
108 }
109 
TEST(SequenceCheckerTest,DifferentThreadSameSequenceToken)110 TEST(SequenceCheckerTest, DifferentThreadSameSequenceToken) {
111   const SequenceToken token = SequenceToken::Create();
112   TaskScope task_scope(token, /* is_thread_bound=*/false);
113   SequenceCheckerImpl sequence_checker;
114   RunCallbackThread thread(BindLambdaForTesting([&]() {
115     TaskScope task_scope(token, /* is_thread_bound=*/false);
116     ExpectCalledOnValidSequence(&sequence_checker);
117   }));
118 }
119 
TEST(SequenceCheckerTest,DifferentThreadSameSequenceTokenThreadBound)120 TEST(SequenceCheckerTest, DifferentThreadSameSequenceTokenThreadBound) {
121   // Note: A callback running synchronously in `RunOrPostTask()` may have a
122   // non-thread-bound `TaskScope` associated with the same `SequenceToken` as
123   // another thread-bound `TaskScope`. This test recreates this case.
124   const SequenceToken token = SequenceToken::Create();
125   TaskScope task_scope(token, /* is_thread_bound=*/true);
126   SequenceCheckerImpl sequence_checker;
127   RunCallbackThread thread(BindLambdaForTesting([&]() {
128     TaskScope task_scope(token, /* is_thread_bound=*/false);
129     ExpectCalledOnValidSequence(&sequence_checker);
130   }));
131 }
132 
TEST(SequenceCheckerTest,SameThreadDifferentSequenceToken)133 TEST(SequenceCheckerTest, SameThreadDifferentSequenceToken) {
134   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
135 
136   {
137     TaskScope task_scope(SequenceToken::Create(),
138                          /* is_thread_bound=*/false);
139     sequence_checker = std::make_unique<SequenceCheckerImpl>();
140   }
141 
142   {
143     // Different SequenceToken.
144     TaskScope task_scope(SequenceToken::Create(),
145                          /* is_thread_bound=*/false);
146     EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
147   }
148 
149   // No explicit SequenceToken.
150   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
151 }
152 
TEST(SequenceCheckerTest,DetachFromSequence)153 TEST(SequenceCheckerTest, DetachFromSequence) {
154   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
155 
156   {
157     TaskScope task_scope(SequenceToken::Create(),
158                          /* is_thread_bound=*/false);
159     sequence_checker = std::make_unique<SequenceCheckerImpl>();
160   }
161 
162   sequence_checker->DetachFromSequence();
163 
164   {
165     // Verify that CalledOnValidSequence() returns true when called with
166     // a different sequence token after a call to DetachFromSequence().
167     TaskScope task_scope(SequenceToken::Create(),
168                          /* is_thread_bound=*/false);
169     EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
170   }
171 }
172 
TEST(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)173 TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
174   SequenceCheckerImpl sequence_checker;
175   sequence_checker.DetachFromSequence();
176 
177   // Verify that CalledOnValidSequence() returns true when called on a
178   // different thread after a call to DetachFromSequence().
179   RunCallbackThread thread(
180       BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
181 
182   EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
183 }
184 
TEST(SequenceCheckerTest,Move)185 TEST(SequenceCheckerTest, Move) {
186   SequenceCheckerImpl initial;
187   EXPECT_TRUE(initial.CalledOnValidSequence());
188 
189   SequenceCheckerImpl move_constructed(std::move(initial));
190   EXPECT_TRUE(move_constructed.CalledOnValidSequence());
191 
192   SequenceCheckerImpl move_assigned;
193   move_assigned = std::move(move_constructed);
194 
195   // The two SequenceCheckerImpls moved from should be able to rebind to another
196   // sequence.
197   RunCallbackThread thread1(
198       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
199   RunCallbackThread thread2(
200       BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
201 
202   // But the latest one shouldn't be able to run on another sequence.
203   RunCallbackThread thread(
204       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
205 
206   EXPECT_TRUE(move_assigned.CalledOnValidSequence());
207 }
208 
TEST(SequenceCheckerTest,MoveAssignIntoDetached)209 TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
210   SequenceCheckerImpl initial;
211 
212   SequenceCheckerImpl move_assigned;
213   move_assigned.DetachFromSequence();
214   move_assigned = std::move(initial);
215 
216   // |initial| is detached after move.
217   RunCallbackThread thread1(
218       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
219 
220   // |move_assigned| should be associated with the main thread.
221   RunCallbackThread thread2(
222       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
223 
224   EXPECT_TRUE(move_assigned.CalledOnValidSequence());
225 }
226 
TEST(SequenceCheckerTest,MoveFromDetachedRebinds)227 TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
228   SequenceCheckerImpl initial;
229   initial.DetachFromSequence();
230 
231   SequenceCheckerImpl moved_into(std::move(initial));
232 
233   // |initial| is still detached after move.
234   RunCallbackThread thread1(
235       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
236 
237   // |moved_into| is bound to the current sequence as part of the move.
238   RunCallbackThread thread2(
239       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
240   EXPECT_TRUE(moved_into.CalledOnValidSequence());
241 }
242 
TEST(SequenceCheckerTest,MoveOffSequenceBanned)243 TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
244   GTEST_FLAG_SET(death_test_style, "threadsafe");
245 
246   SequenceCheckerImpl other_sequence;
247   other_sequence.DetachFromSequence();
248   RunCallbackThread thread(
249       BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
250 
251   EXPECT_DCHECK_DEATH(
252       SequenceCheckerImpl main_sequence(std::move(other_sequence)));
253 }
254 
TEST(SequenceCheckerMacroTest,Macros)255 TEST(SequenceCheckerMacroTest, Macros) {
256   auto scope = std::make_unique<TaskScope>(SequenceToken::Create(),
257                                            /* is_thread_bound=*/false);
258   SEQUENCE_CHECKER(my_sequence_checker);
259 
260   {
261     // Don't expect a DCHECK death when a SequenceChecker is used on the right
262     // sequence.
263     DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
264   }
265   scope.reset();
266 
267 #if DCHECK_IS_ON()
268   // Expect DCHECK death when used on a different sequence.
269   EXPECT_DCHECK_DEATH(
270       { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
271 #else
272     // Happily no-ops on non-dcheck builds.
273   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
274 #endif
275 
276   DETACH_FROM_SEQUENCE(my_sequence_checker);
277 
278   // Don't expect a DCHECK death when a SequenceChecker is used for the first
279   // time after having been detached.
280   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
281 }
282 
283 // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
284 // in ~SequenceCheckerOwner.
285 class SequenceCheckerOwner {
286  public:
SequenceCheckerOwner(SequenceCheckerImpl * other_checker)287   explicit SequenceCheckerOwner(SequenceCheckerImpl* other_checker)
288       : other_checker_(other_checker) {}
289   SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
290   SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
~SequenceCheckerOwner()291   ~SequenceCheckerOwner() {
292     // Check passes on TLS destruction.
293     EXPECT_TRUE(checker_.CalledOnValidSequence());
294 
295     // Check also passes on TLS destruction after move assignment.
296     *other_checker_ = std::move(checker_);
297     EXPECT_TRUE(other_checker_->CalledOnValidSequence());
298   }
299 
300  private:
301   SequenceCheckerImpl checker_;
302   raw_ptr<SequenceCheckerImpl> other_checker_;
303 };
304 
305 // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
306 // during thread destruction.
TEST(SequenceCheckerTest,FromThreadDestruction)307 TEST(SequenceCheckerTest, FromThreadDestruction) {
308   SequenceChecker::EnableStackLogging();
309 
310   SequenceCheckerImpl other_checker;
311   ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
312   {
313     test::TaskEnvironment task_environment;
314     auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
315     task_runner->PostTask(
316         FROM_HERE, BindLambdaForTesting([&]() {
317           thread_local_owner.Set(
318               std::make_unique<SequenceCheckerOwner>(&other_checker));
319         }));
320     task_runner = nullptr;
321     task_environment.RunUntilIdle();
322   }
323 }
324 
325 }  // namespace base::internal
326