Home | History | Annotate | Download | only in browser
      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 "content/browser/startup_task_runner.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback.h"
     10 #include "base/location.h"
     11 #include "base/run_loop.h"
     12 #include "base/task_runner.h"
     13 
     14 #include "testing/gmock/include/gmock/gmock.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace content {
     18 namespace {
     19 
     20 using base::Closure;
     21 using testing::_;
     22 using testing::Assign;
     23 using testing::Invoke;
     24 using testing::WithArg;
     25 
     26 bool observer_called = false;
     27 int observer_result;
     28 base::Closure task;
     29 
     30 // I couldn't get gMock's SaveArg to compile, hence had to save the argument
     31 // this way
     32 bool SaveTaskArg(const Closure& arg) {
     33   task = arg;
     34   return true;
     35 }
     36 
     37 void Observer(int result) {
     38   observer_called = true;
     39   observer_result = result;
     40 }
     41 
     42 class StartupTaskRunnerTest : public testing::Test {
     43  public:
     44 
     45   virtual void SetUp() {
     46     last_task_ = 0;
     47     observer_called = false;
     48   }
     49 
     50   int Task1() {
     51     last_task_ = 1;
     52     return 0;
     53   }
     54 
     55   int Task2() {
     56     last_task_ = 2;
     57     return 0;
     58   }
     59 
     60   int FailingTask() {
     61     // Task returning failure
     62     last_task_ = 3;
     63     return 1;
     64   }
     65 
     66   int GetLastTask() { return last_task_; }
     67 
     68  private:
     69 
     70   int last_task_;
     71 };
     72 
     73 // We can't use the real message loop, even if we want to, since doing so on
     74 // Android requires a complex Java infrastructure. The test would have to built
     75 // as a content_shell test; but content_shell startup invokes the class we are
     76 // trying to test.
     77 //
     78 // The mocks are not directly in TaskRunnerProxy because reference counted
     79 // objects seem to confuse the mocking framework
     80 
     81 class MockTaskRunner {
     82  public:
     83   MOCK_METHOD3(
     84       PostDelayedTask,
     85       bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
     86   MOCK_METHOD3(
     87       PostNonNestableDelayedTask,
     88       bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
     89 };
     90 
     91 class TaskRunnerProxy : public base::SingleThreadTaskRunner {
     92  public:
     93   TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
     94   virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; }
     95   virtual bool PostDelayedTask(const tracked_objects::Location& location,
     96                                const Closure& closure,
     97                                base::TimeDelta delta) OVERRIDE {
     98     return mock_->PostDelayedTask(location, closure, delta);
     99   }
    100   virtual bool PostNonNestableDelayedTask(
    101       const tracked_objects::Location& location,
    102       const Closure& closure,
    103       base::TimeDelta delta) OVERRIDE {
    104     return mock_->PostNonNestableDelayedTask(location, closure, delta);
    105   }
    106 
    107  private:
    108   MockTaskRunner* mock_;
    109   virtual ~TaskRunnerProxy() {}
    110 };
    111 
    112 TEST_F(StartupTaskRunnerTest, SynchronousExecution) {
    113   MockTaskRunner mock_runner;
    114   scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
    115 
    116   EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
    117   EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
    118 
    119   scoped_refptr<StartupTaskRunner> runner =
    120       new StartupTaskRunner(false, base::Bind(&Observer), proxy);
    121 
    122   StartupTask task1 =
    123       base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
    124   runner->AddTask(task1);
    125   EXPECT_EQ(GetLastTask(), 0);
    126   StartupTask task2 =
    127       base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
    128   runner->AddTask(task2);
    129 
    130   // Nothing should run until we tell them to.
    131   EXPECT_EQ(GetLastTask(), 0);
    132   runner->StartRunningTasks();
    133 
    134   // On an immediate StartupTaskRunner the tasks should now all have run.
    135   EXPECT_EQ(GetLastTask(), 2);
    136 
    137   EXPECT_TRUE(observer_called);
    138   EXPECT_EQ(observer_result, 0);
    139 }
    140 
    141 TEST_F(StartupTaskRunnerTest, NullObserver) {
    142   MockTaskRunner mock_runner;
    143   scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
    144 
    145   EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
    146   EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
    147 
    148   scoped_refptr<StartupTaskRunner> runner =
    149       new StartupTaskRunner(false, base::Callback<void(int)>(), proxy);
    150 
    151   StartupTask task1 =
    152       base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
    153   runner->AddTask(task1);
    154   EXPECT_EQ(GetLastTask(), 0);
    155   StartupTask task2 =
    156       base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
    157   runner->AddTask(task2);
    158 
    159   // Nothing should run until we tell them to.
    160   EXPECT_EQ(GetLastTask(), 0);
    161   runner->StartRunningTasks();
    162 
    163   // On an immediate StartupTaskRunner the tasks should now all have run.
    164   EXPECT_EQ(GetLastTask(), 2);
    165 
    166   EXPECT_FALSE(observer_called);
    167 }
    168 
    169 TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) {
    170   MockTaskRunner mock_runner;
    171   scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
    172 
    173   EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
    174   EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
    175 
    176   scoped_refptr<StartupTaskRunner> runner =
    177       new StartupTaskRunner(false, base::Bind(&Observer), proxy);
    178 
    179   StartupTask task3 =
    180       base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
    181   runner->AddTask(task3);
    182   EXPECT_EQ(GetLastTask(), 0);
    183   StartupTask task2 =
    184       base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
    185   runner->AddTask(task2);
    186 
    187   // Nothing should run until we tell them to.
    188   EXPECT_EQ(GetLastTask(), 0);
    189   runner->StartRunningTasks();
    190 
    191   // Only the first task should have run, since it failed
    192   EXPECT_EQ(GetLastTask(), 3);
    193 
    194   EXPECT_TRUE(observer_called);
    195   EXPECT_EQ(observer_result, 1);
    196 }
    197 
    198 TEST_F(StartupTaskRunnerTest, AsynchronousExecution) {
    199 
    200   MockTaskRunner mock_runner;
    201   scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
    202 
    203   EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
    204   EXPECT_CALL(
    205       mock_runner,
    206       PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
    207       .Times(testing::Between(2, 3))
    208       .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
    209 
    210   scoped_refptr<StartupTaskRunner> runner =
    211       new StartupTaskRunner(true, base::Bind(&Observer), proxy);
    212 
    213   StartupTask task1 =
    214       base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
    215   runner->AddTask(task1);
    216   StartupTask task2 =
    217       base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
    218   runner->AddTask(task2);
    219 
    220   // Nothing should run until we tell them to.
    221   EXPECT_EQ(GetLastTask(), 0);
    222   runner->StartRunningTasks();
    223 
    224   // No tasks should have run yet, since we the message loop hasn't run.
    225   EXPECT_EQ(GetLastTask(), 0);
    226 
    227   // Fake the actual message loop. Each time a task is run a new task should
    228   // be added to the queue, hence updating "task". The loop should actually run
    229   // at most 3 times (once for each task plus possibly once for the observer),
    230   // the "4" is a backstop.
    231   for (int i = 0; i < 4 && !observer_called; i++) {
    232     task.Run();
    233     EXPECT_EQ(i + 1, GetLastTask());
    234   }
    235   EXPECT_TRUE(observer_called);
    236   EXPECT_EQ(observer_result, 0);
    237 }
    238 
    239 TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) {
    240 
    241   MockTaskRunner mock_runner;
    242   scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
    243 
    244   EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
    245   EXPECT_CALL(
    246       mock_runner,
    247       PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
    248       .Times(testing::Between(1, 2))
    249       .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
    250 
    251   scoped_refptr<StartupTaskRunner> runner =
    252       new StartupTaskRunner(true, base::Bind(&Observer), proxy);
    253 
    254   StartupTask task3 =
    255       base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
    256   runner->AddTask(task3);
    257   StartupTask task2 =
    258       base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
    259   runner->AddTask(task2);
    260 
    261   // Nothing should run until we tell them to.
    262   EXPECT_EQ(GetLastTask(), 0);
    263   runner->StartRunningTasks();
    264 
    265   // No tasks should have run yet, since we the message loop hasn't run.
    266   EXPECT_EQ(GetLastTask(), 0);
    267 
    268   // Fake the actual message loop. Each time a task is run a new task should
    269   // be added to the queue, hence updating "task". The loop should actually run
    270   // at most twice (once for the failed task plus possibly once for the
    271   // observer), the "4" is a backstop.
    272   for (int i = 0; i < 4 && !observer_called; i++) {
    273     task.Run();
    274   }
    275   EXPECT_EQ(GetLastTask(), 3);
    276 
    277   EXPECT_TRUE(observer_called);
    278   EXPECT_EQ(observer_result, 1);
    279 }
    280 }  // namespace
    281 }  // namespace content
    282