Home | History | Annotate | Download | only in base
      1 // Copyright (c) 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/deferred_sequenced_task_runner.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/bind_helpers.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/message_loop/message_loop_proxy.h"
     13 #include "base/threading/non_thread_safe.h"
     14 #include "base/threading/thread.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace {
     19 
     20 class DeferredSequencedTaskRunnerTest : public testing::Test,
     21                                         public base::NonThreadSafe {
     22  public:
     23   class ExecuteTaskOnDestructor :
     24       public base::RefCounted<ExecuteTaskOnDestructor> {
     25    public:
     26     ExecuteTaskOnDestructor(
     27         DeferredSequencedTaskRunnerTest* executor,
     28         int task_id)
     29         : executor_(executor),
     30           task_id_(task_id) {
     31     }
     32   private:
     33     friend class base::RefCounted<ExecuteTaskOnDestructor>;
     34     virtual ~ExecuteTaskOnDestructor() {
     35       executor_->ExecuteTask(task_id_);
     36     }
     37     DeferredSequencedTaskRunnerTest* executor_;
     38     int task_id_;
     39   };
     40 
     41   void ExecuteTask(int task_id) {
     42     base::AutoLock lock(lock_);
     43     executed_task_ids_.push_back(task_id);
     44   }
     45 
     46   void PostExecuteTask(int task_id) {
     47     runner_->PostTask(FROM_HERE,
     48                       base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask,
     49                                  base::Unretained(this),
     50                                  task_id));
     51   }
     52 
     53   void StartRunner() {
     54     runner_->Start();
     55   }
     56 
     57   void DoNothing(ExecuteTaskOnDestructor* object) {
     58   }
     59 
     60  protected:
     61   DeferredSequencedTaskRunnerTest() :
     62       loop_(),
     63       runner_(
     64           new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) {
     65   }
     66 
     67   base::MessageLoop loop_;
     68   scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
     69   mutable base::Lock lock_;
     70   std::vector<int> executed_task_ids_;
     71 };
     72 
     73 TEST_F(DeferredSequencedTaskRunnerTest, Stopped) {
     74   PostExecuteTask(1);
     75   loop_.RunUntilIdle();
     76   EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
     77 }
     78 
     79 TEST_F(DeferredSequencedTaskRunnerTest, Start) {
     80   StartRunner();
     81   PostExecuteTask(1);
     82   loop_.RunUntilIdle();
     83   EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
     84 }
     85 
     86 TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) {
     87   StartRunner();
     88   for (int i = 1; i < 5; ++i)
     89     PostExecuteTask(i);
     90 
     91   loop_.RunUntilIdle();
     92   EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4));
     93 }
     94 
     95 TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) {
     96   PostExecuteTask(1);
     97   loop_.RunUntilIdle();
     98   EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
     99 
    100   StartRunner();
    101   loop_.RunUntilIdle();
    102   EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
    103 
    104   PostExecuteTask(2);
    105   loop_.RunUntilIdle();
    106   EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2));
    107 }
    108 
    109 TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) {
    110   for (int i = 1; i < 5; ++i)
    111     PostExecuteTask(i);
    112   loop_.RunUntilIdle();
    113   EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
    114 
    115   StartRunner();
    116   for (int i = 5; i < 9; ++i)
    117     PostExecuteTask(i);
    118   loop_.RunUntilIdle();
    119   EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8));
    120 }
    121 
    122 TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) {
    123   {
    124     base::Thread thread1("DeferredSequencedTaskRunnerTestThread1");
    125     base::Thread thread2("DeferredSequencedTaskRunnerTestThread2");
    126     thread1.Start();
    127     thread2.Start();
    128     for (int i = 0; i < 5; ++i) {
    129       thread1.message_loop()->PostTask(
    130           FROM_HERE,
    131           base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
    132                      base::Unretained(this),
    133                      2 * i));
    134       thread2.message_loop()->PostTask(
    135           FROM_HERE,
    136           base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
    137                      base::Unretained(this),
    138                      2 * i + 1));
    139       if (i == 2) {
    140         thread1.message_loop()->PostTask(
    141             FROM_HERE,
    142             base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
    143                        base::Unretained(this)));
    144       }
    145     }
    146   }
    147 
    148   loop_.RunUntilIdle();
    149   EXPECT_THAT(executed_task_ids_,
    150       testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)));
    151 }
    152 
    153 TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) {
    154   {
    155     base::Thread thread("DeferredSequencedTaskRunnerTestThread");
    156     thread.Start();
    157     runner_ =
    158         new base::DeferredSequencedTaskRunner(thread.message_loop_proxy());
    159     for (int i = 0; i < 5; ++i) {
    160       {
    161         // Use a block to ensure that no reference to |short_lived_object|
    162         // is kept on the main thread after it is posted to |runner_|.
    163         scoped_refptr<ExecuteTaskOnDestructor> short_lived_object =
    164             new ExecuteTaskOnDestructor(this, 2 * i);
    165         runner_->PostTask(
    166             FROM_HERE,
    167             base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing,
    168                        base::Unretained(this),
    169                        short_lived_object));
    170       }
    171       // |short_lived_object| with id |2 * i| should be destroyed before the
    172       // task |2 * i + 1| is executed.
    173       PostExecuteTask(2 * i + 1);
    174     }
    175     StartRunner();
    176   }
    177 
    178   // All |short_lived_object| with id |2 * i| are destroyed before the task
    179   // |2 * i + 1| is executed.
    180   EXPECT_THAT(executed_task_ids_,
    181               testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
    182 }
    183 
    184 }  // namespace
    185