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