Home | History | Annotate | Download | only in base
      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