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 <stddef.h>
6
7 #include <memory>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback_forward.h"
13 #include "base/macros.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/sequence_checker_impl.h"
16 #include "base/sequence_token.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/test/sequenced_worker_pool_owner.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 constexpr size_t kNumWorkerThreads = 3;
27
28 // Runs a callback on another thread.
29 class RunCallbackThread : public SimpleThread {
30 public:
RunCallbackThread(const Closure & callback)31 explicit RunCallbackThread(const Closure& callback)
32 : SimpleThread("RunCallbackThread"), callback_(callback) {
33 Start();
34 Join();
35 }
36
37 private:
38 // SimpleThread:
Run()39 void Run() override { callback_.Run(); }
40
41 const Closure callback_;
42
43 DISALLOW_COPY_AND_ASSIGN(RunCallbackThread);
44 };
45
46 class SequenceCheckerTest : public testing::Test {
47 protected:
SequenceCheckerTest()48 SequenceCheckerTest() : pool_owner_(kNumWorkerThreads, "test") {}
49
PostToSequencedWorkerPool(const Closure & callback,const std::string & token_name)50 void PostToSequencedWorkerPool(const Closure& callback,
51 const std::string& token_name) {
52 pool_owner_.pool()->PostNamedSequencedWorkerTask(token_name, FROM_HERE,
53 callback);
54 }
55
FlushSequencedWorkerPoolForTesting()56 void FlushSequencedWorkerPoolForTesting() {
57 pool_owner_.pool()->FlushForTesting();
58 }
59
60 private:
61 MessageLoop message_loop_; // Needed by SequencedWorkerPool to function.
62 SequencedWorkerPoolOwner pool_owner_;
63
64 DISALLOW_COPY_AND_ASSIGN(SequenceCheckerTest);
65 };
66
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)67 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
68 ASSERT_TRUE(sequence_checker);
69
70 // This should bind |sequence_checker| to the current sequence if it wasn't
71 // already bound to a sequence.
72 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
73
74 // Since |sequence_checker| is now bound to the current sequence, another call
75 // to CalledOnValidSequence() should return true.
76 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
77 }
78
ExpectCalledOnValidSequenceWithSequenceToken(SequenceCheckerImpl * sequence_checker,SequenceToken sequence_token)79 void ExpectCalledOnValidSequenceWithSequenceToken(
80 SequenceCheckerImpl* sequence_checker,
81 SequenceToken sequence_token) {
82 ScopedSetSequenceTokenForCurrentThread
83 scoped_set_sequence_token_for_current_thread(sequence_token);
84 ExpectCalledOnValidSequence(sequence_checker);
85 }
86
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)87 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
88 ASSERT_TRUE(sequence_checker);
89 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
90 }
91
92 } // namespace
93
TEST_F(SequenceCheckerTest,CallsAllowedOnSameThreadNoSequenceToken)94 TEST_F(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) {
95 SequenceCheckerImpl sequence_checker;
96 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
97 }
98
TEST_F(SequenceCheckerTest,CallsAllowedOnSameThreadSameSequenceToken)99 TEST_F(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) {
100 ScopedSetSequenceTokenForCurrentThread
101 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
102 SequenceCheckerImpl sequence_checker;
103 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
104 }
105
TEST_F(SequenceCheckerTest,CallsDisallowedOnDifferentThreadsNoSequenceToken)106 TEST_F(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) {
107 SequenceCheckerImpl sequence_checker;
108 RunCallbackThread thread(
109 Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
110 }
111
TEST_F(SequenceCheckerTest,CallsAllowedOnDifferentThreadsSameSequenceToken)112 TEST_F(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) {
113 const SequenceToken sequence_token(SequenceToken::Create());
114
115 ScopedSetSequenceTokenForCurrentThread
116 scoped_set_sequence_token_for_current_thread(sequence_token);
117 SequenceCheckerImpl sequence_checker;
118 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
119
120 RunCallbackThread thread(Bind(&ExpectCalledOnValidSequenceWithSequenceToken,
121 Unretained(&sequence_checker), sequence_token));
122 }
123
TEST_F(SequenceCheckerTest,CallsDisallowedOnSameThreadDifferentSequenceToken)124 TEST_F(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) {
125 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
126
127 {
128 ScopedSetSequenceTokenForCurrentThread
129 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
130 sequence_checker.reset(new SequenceCheckerImpl);
131 }
132
133 {
134 // Different SequenceToken.
135 ScopedSetSequenceTokenForCurrentThread
136 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
137 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
138 }
139
140 // No SequenceToken.
141 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
142 }
143
TEST_F(SequenceCheckerTest,DetachFromSequence)144 TEST_F(SequenceCheckerTest, DetachFromSequence) {
145 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
146
147 {
148 ScopedSetSequenceTokenForCurrentThread
149 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
150 sequence_checker.reset(new SequenceCheckerImpl);
151 }
152
153 sequence_checker->DetachFromSequence();
154
155 {
156 // Verify that CalledOnValidSequence() returns true when called with
157 // a different sequence token after a call to DetachFromSequence().
158 ScopedSetSequenceTokenForCurrentThread
159 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
160 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
161 }
162 }
163
TEST_F(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)164 TEST_F(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
165 SequenceCheckerImpl sequence_checker;
166 sequence_checker.DetachFromSequence();
167
168 // Verify that CalledOnValidSequence() returns true when called on a
169 // different thread after a call to DetachFromSequence().
170 RunCallbackThread thread(
171 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
172
173 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
174 }
175
TEST_F(SequenceCheckerTest,SequencedWorkerPool_SameSequenceTokenValid)176 TEST_F(SequenceCheckerTest, SequencedWorkerPool_SameSequenceTokenValid) {
177 SequenceCheckerImpl sequence_checker;
178 sequence_checker.DetachFromSequence();
179
180 PostToSequencedWorkerPool(
181 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
182 PostToSequencedWorkerPool(
183 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
184 FlushSequencedWorkerPoolForTesting();
185 }
186
TEST_F(SequenceCheckerTest,SequencedWorkerPool_DetachSequenceTokenValid)187 TEST_F(SequenceCheckerTest, SequencedWorkerPool_DetachSequenceTokenValid) {
188 SequenceCheckerImpl sequence_checker;
189 sequence_checker.DetachFromSequence();
190
191 PostToSequencedWorkerPool(
192 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
193 PostToSequencedWorkerPool(
194 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
195 FlushSequencedWorkerPoolForTesting();
196
197 sequence_checker.DetachFromSequence();
198
199 PostToSequencedWorkerPool(
200 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "B");
201 PostToSequencedWorkerPool(
202 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "B");
203 FlushSequencedWorkerPoolForTesting();
204 }
205
TEST_F(SequenceCheckerTest,SequencedWorkerPool_DifferentSequenceTokensInvalid)206 TEST_F(SequenceCheckerTest,
207 SequencedWorkerPool_DifferentSequenceTokensInvalid) {
208 SequenceCheckerImpl sequence_checker;
209 sequence_checker.DetachFromSequence();
210
211 PostToSequencedWorkerPool(
212 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
213 PostToSequencedWorkerPool(
214 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
215 FlushSequencedWorkerPoolForTesting();
216
217 PostToSequencedWorkerPool(
218 Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)),
219 "B");
220 PostToSequencedWorkerPool(
221 Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)),
222 "B");
223 FlushSequencedWorkerPoolForTesting();
224 }
225
TEST_F(SequenceCheckerTest,SequencedWorkerPool_WorkerPoolAndSimpleThreadInvalid)226 TEST_F(SequenceCheckerTest,
227 SequencedWorkerPool_WorkerPoolAndSimpleThreadInvalid) {
228 SequenceCheckerImpl sequence_checker;
229 sequence_checker.DetachFromSequence();
230
231 PostToSequencedWorkerPool(
232 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
233 PostToSequencedWorkerPool(
234 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
235 FlushSequencedWorkerPoolForTesting();
236
237 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
238 }
239
TEST_F(SequenceCheckerTest,SequencedWorkerPool_TwoDifferentWorkerPoolsInvalid)240 TEST_F(SequenceCheckerTest,
241 SequencedWorkerPool_TwoDifferentWorkerPoolsInvalid) {
242 SequenceCheckerImpl sequence_checker;
243 sequence_checker.DetachFromSequence();
244
245 PostToSequencedWorkerPool(
246 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
247 PostToSequencedWorkerPool(
248 Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)), "A");
249 FlushSequencedWorkerPoolForTesting();
250
251 SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2");
252 second_pool_owner.pool()->PostNamedSequencedWorkerTask(
253 "A", FROM_HERE, base::Bind(&ExpectNotCalledOnValidSequence,
254 base::Unretained(&sequence_checker)));
255 second_pool_owner.pool()->FlushForTesting();
256 }
257
258 } // namespace base
259