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