1 // Copyright 2013 The Chromium Authors. All rights reserved.
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 
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback_forward.h"
15 #include "base/macros.h"
16 #include "base/sequence_token.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/test/gtest_util.h"
19 #include "base/threading/simple_thread.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace base {
23 
24 namespace {
25 
26 // Runs a callback on another thread.
27 class RunCallbackThread : public SimpleThread {
28  public:
RunCallbackThread(const Closure & callback)29   explicit RunCallbackThread(const Closure& callback)
30       : SimpleThread("RunCallbackThread"), callback_(callback) {
31     Start();
32     Join();
33   }
34 
35  private:
36   // SimpleThread:
Run()37   void Run() override { callback_.Run(); }
38 
39   const Closure callback_;
40 
41   DISALLOW_COPY_AND_ASSIGN(RunCallbackThread);
42 };
43 
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)44 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
45   ASSERT_TRUE(sequence_checker);
46 
47   // This should bind |sequence_checker| to the current sequence if it wasn't
48   // already bound to a sequence.
49   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
50 
51   // Since |sequence_checker| is now bound to the current sequence, another call
52   // to CalledOnValidSequence() should return true.
53   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
54 }
55 
ExpectCalledOnValidSequenceWithSequenceToken(SequenceCheckerImpl * sequence_checker,SequenceToken sequence_token)56 void ExpectCalledOnValidSequenceWithSequenceToken(
57     SequenceCheckerImpl* sequence_checker,
58     SequenceToken sequence_token) {
59   ScopedSetSequenceTokenForCurrentThread
60       scoped_set_sequence_token_for_current_thread(sequence_token);
61   ExpectCalledOnValidSequence(sequence_checker);
62 }
63 
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)64 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
65   ASSERT_TRUE(sequence_checker);
66   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
67 }
68 
69 }  // namespace
70 
TEST(SequenceCheckerTest,CallsAllowedOnSameThreadNoSequenceToken)71 TEST(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) {
72   SequenceCheckerImpl sequence_checker;
73   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
74 }
75 
TEST(SequenceCheckerTest,CallsAllowedOnSameThreadSameSequenceToken)76 TEST(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) {
77   ScopedSetSequenceTokenForCurrentThread
78       scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
79   SequenceCheckerImpl sequence_checker;
80   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
81 }
82 
TEST(SequenceCheckerTest,CallsDisallowedOnDifferentThreadsNoSequenceToken)83 TEST(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) {
84   SequenceCheckerImpl sequence_checker;
85   RunCallbackThread thread(
86       Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
87 }
88 
TEST(SequenceCheckerTest,CallsAllowedOnDifferentThreadsSameSequenceToken)89 TEST(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) {
90   const SequenceToken sequence_token(SequenceToken::Create());
91 
92   ScopedSetSequenceTokenForCurrentThread
93       scoped_set_sequence_token_for_current_thread(sequence_token);
94   SequenceCheckerImpl sequence_checker;
95   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
96 
97   RunCallbackThread thread(Bind(&ExpectCalledOnValidSequenceWithSequenceToken,
98                                 Unretained(&sequence_checker), sequence_token));
99 }
100 
TEST(SequenceCheckerTest,CallsDisallowedOnSameThreadDifferentSequenceToken)101 TEST(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) {
102   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
103 
104   {
105     ScopedSetSequenceTokenForCurrentThread
106         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
107     sequence_checker.reset(new SequenceCheckerImpl);
108   }
109 
110   {
111     // Different SequenceToken.
112     ScopedSetSequenceTokenForCurrentThread
113         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
114     EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
115   }
116 
117   // No SequenceToken.
118   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
119 }
120 
TEST(SequenceCheckerTest,DetachFromSequence)121 TEST(SequenceCheckerTest, DetachFromSequence) {
122   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
123 
124   {
125     ScopedSetSequenceTokenForCurrentThread
126         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
127     sequence_checker.reset(new SequenceCheckerImpl);
128   }
129 
130   sequence_checker->DetachFromSequence();
131 
132   {
133     // Verify that CalledOnValidSequence() returns true when called with
134     // a different sequence token after a call to DetachFromSequence().
135     ScopedSetSequenceTokenForCurrentThread
136         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
137     EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
138   }
139 }
140 
TEST(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)141 TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
142   SequenceCheckerImpl sequence_checker;
143   sequence_checker.DetachFromSequence();
144 
145   // Verify that CalledOnValidSequence() returns true when called on a
146   // different thread after a call to DetachFromSequence().
147   RunCallbackThread thread(
148       Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
149 
150   EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
151 }
152 
TEST(SequenceCheckerMacroTest,Macros)153 TEST(SequenceCheckerMacroTest, Macros) {
154   auto scope = std::make_unique<ScopedSetSequenceTokenForCurrentThread>(
155       SequenceToken::Create());
156   SEQUENCE_CHECKER(my_sequence_checker);
157 
158   // Don't expect a DCHECK death when a SequenceChecker is used on the right
159   // sequence.
160   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
161 
162   scope.reset();
163 
164 #if DCHECK_IS_ON()
165   // Expect DCHECK death when used on a different sequence.
166   EXPECT_DCHECK_DEATH({
167     DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
168   });
169 #else
170     // Happily no-ops on non-dcheck builds.
171     DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
172 #endif
173 
174   DETACH_FROM_SEQUENCE(my_sequence_checker);
175 
176   // Don't expect a DCHECK death when a SequenceChecker is used for the first
177   // time after having been detached.
178   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
179 }
180 
181 }  // namespace base
182