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: 31 explicit RunCallbackThread(const Closure& callback) 32 : SimpleThread("RunCallbackThread"), callback_(callback) { 33 Start(); 34 Join(); 35 } 36 37 private: 38 // SimpleThread: 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: 48 SequenceCheckerTest() : pool_owner_(kNumWorkerThreads, "test") {} 49 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 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 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 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 87 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) { 88 ASSERT_TRUE(sequence_checker); 89 EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); 90 } 91 92 } // namespace 93 94 TEST_F(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) { 95 SequenceCheckerImpl sequence_checker; 96 EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); 97 } 98 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 106 TEST_F(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) { 107 SequenceCheckerImpl sequence_checker; 108 RunCallbackThread thread( 109 Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker))); 110 } 111 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 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 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 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 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 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 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 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 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