Home | History | Annotate | Download | only in base
      1 // Copyright 2014 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 <deque>
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/test/test_pending_task.h"
     10 #include "base/test/test_simple_task_runner.h"
     11 #include "cc/base/delayed_unique_notifier.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace cc {
     15 namespace {
     16 
     17 class TestNotifier : public DelayedUniqueNotifier {
     18  public:
     19   TestNotifier(base::SequencedTaskRunner* task_runner,
     20                const base::Closure& closure,
     21                const base::TimeDelta& delay)
     22       : DelayedUniqueNotifier(task_runner, closure, delay) {}
     23   virtual ~TestNotifier() {}
     24 
     25   // Overridden from DelayedUniqueNotifier:
     26   virtual base::TimeTicks Now() const OVERRIDE { return now_; }
     27 
     28   void SetNow(base::TimeTicks now) { now_ = now; }
     29 
     30  private:
     31   base::TimeTicks now_;
     32 };
     33 
     34 class DelayedUniqueNotifierTest : public testing::Test {
     35  public:
     36   DelayedUniqueNotifierTest() : notification_count_(0) {}
     37 
     38   virtual void SetUp() OVERRIDE {
     39     notification_count_ = 0;
     40     task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
     41   }
     42 
     43   void Notify() { ++notification_count_; }
     44 
     45   int NotificationCount() const { return notification_count_; }
     46 
     47   std::deque<base::TestPendingTask> TakePendingTasks() {
     48     std::deque<base::TestPendingTask> tasks = task_runner_->GetPendingTasks();
     49     task_runner_->ClearPendingTasks();
     50     return tasks;
     51   }
     52 
     53  protected:
     54   int notification_count_;
     55   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
     56 };
     57 
     58 TEST_F(DelayedUniqueNotifierTest, ZeroDelay) {
     59   base::TimeDelta delay = base::TimeDelta::FromInternalValue(0);
     60   TestNotifier notifier(
     61       task_runner_,
     62       base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
     63       delay);
     64 
     65   EXPECT_EQ(0, NotificationCount());
     66 
     67   // Basic schedule for |delay| from now.
     68   base::TimeTicks schedule_time =
     69       base::TimeTicks() + base::TimeDelta::FromInternalValue(10);
     70 
     71   notifier.SetNow(schedule_time);
     72   notifier.Schedule();
     73 
     74   std::deque<base::TestPendingTask> tasks = TakePendingTasks();
     75   ASSERT_EQ(1u, tasks.size());
     76   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
     77 
     78   tasks[0].task.Run();
     79   EXPECT_EQ(1, NotificationCount());
     80 
     81   // 5 schedules should result in only one run.
     82   for (int i = 0; i < 5; ++i)
     83     notifier.Schedule();
     84 
     85   tasks = TakePendingTasks();
     86   ASSERT_EQ(1u, tasks.size());
     87   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
     88 
     89   tasks[0].task.Run();
     90   EXPECT_EQ(2, NotificationCount());
     91 }
     92 
     93 TEST_F(DelayedUniqueNotifierTest, SmallDelay) {
     94   base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
     95   TestNotifier notifier(
     96       task_runner_,
     97       base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
     98       delay);
     99 
    100   EXPECT_EQ(0, NotificationCount());
    101 
    102   // Basic schedule for |delay| from now (now: 30, run time: 50).
    103   base::TimeTicks schedule_time =
    104       base::TimeTicks() + base::TimeDelta::FromInternalValue(30);
    105 
    106   notifier.SetNow(schedule_time);
    107   notifier.Schedule();
    108 
    109   std::deque<base::TestPendingTask> tasks = TakePendingTasks();
    110 
    111   ASSERT_EQ(1u, tasks.size());
    112   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    113 
    114   // It's not yet time to run, so we expect no notifications.
    115   tasks[0].task.Run();
    116   EXPECT_EQ(0, NotificationCount());
    117 
    118   tasks = TakePendingTasks();
    119 
    120   ASSERT_EQ(1u, tasks.size());
    121   // Now the time should be delay minus whatever the value of now happens to be
    122   // (now: 30, run time: 50).
    123   base::TimeTicks scheduled_run_time = notifier.Now() + delay;
    124   base::TimeTicks scheduled_delay =
    125       base::TimeTicks() + (scheduled_run_time - notifier.Now());
    126   EXPECT_EQ(scheduled_delay, tasks[0].GetTimeToRun());
    127 
    128   // Move closer to the run time (time: 49, run time: 50).
    129   notifier.SetNow(notifier.Now() + base::TimeDelta::FromInternalValue(19));
    130 
    131   // It's not yet time to run, so we expect no notifications.
    132   tasks[0].task.Run();
    133   EXPECT_EQ(0, NotificationCount());
    134 
    135   tasks = TakePendingTasks();
    136   ASSERT_EQ(1u, tasks.size());
    137 
    138   // Now the time should be delay minus whatever the value of now happens to be.
    139   scheduled_delay = base::TimeTicks() + (scheduled_run_time - notifier.Now());
    140   EXPECT_EQ(scheduled_delay, tasks[0].GetTimeToRun());
    141 
    142   // Move to exactly the run time (time: 50, run time: 50).
    143   notifier.SetNow(notifier.Now() + base::TimeDelta::FromInternalValue(1));
    144 
    145   // It's time to run!
    146   tasks[0].task.Run();
    147   EXPECT_EQ(1, NotificationCount());
    148 
    149   tasks = TakePendingTasks();
    150   EXPECT_EQ(0u, tasks.size());
    151 }
    152 
    153 TEST_F(DelayedUniqueNotifierTest, RescheduleDelay) {
    154   base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
    155   TestNotifier notifier(
    156       task_runner_,
    157       base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
    158       delay);
    159 
    160   base::TimeTicks schedule_time;
    161   // Move time 19 units forward and reschedule, expecting that we still need to
    162   // run in |delay| time and we don't get a notification.
    163   for (int i = 0; i < 10; ++i) {
    164     EXPECT_EQ(0, NotificationCount());
    165 
    166     // Move time forward 19 units.
    167     schedule_time = notifier.Now() + base::TimeDelta::FromInternalValue(19);
    168     notifier.SetNow(schedule_time);
    169     notifier.Schedule();
    170 
    171     std::deque<base::TestPendingTask> tasks = TakePendingTasks();
    172 
    173     ASSERT_EQ(1u, tasks.size());
    174     EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    175 
    176     // It's not yet time to run, so we expect no notifications.
    177     tasks[0].task.Run();
    178     EXPECT_EQ(0, NotificationCount());
    179   }
    180 
    181   // Move time forward 20 units, expecting a notification.
    182   schedule_time = notifier.Now() + base::TimeDelta::FromInternalValue(20);
    183   notifier.SetNow(schedule_time);
    184 
    185   std::deque<base::TestPendingTask> tasks = TakePendingTasks();
    186 
    187   ASSERT_EQ(1u, tasks.size());
    188   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    189 
    190   // Time to run!
    191   tasks[0].task.Run();
    192   EXPECT_EQ(1, NotificationCount());
    193 }
    194 
    195 TEST_F(DelayedUniqueNotifierTest, CancelAndHasPendingNotification) {
    196   base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
    197   TestNotifier notifier(
    198       task_runner_,
    199       base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
    200       delay);
    201 
    202   EXPECT_EQ(0, NotificationCount());
    203 
    204   // Schedule for |delay| seconds from now.
    205   base::TimeTicks schedule_time =
    206       notifier.Now() + base::TimeDelta::FromInternalValue(10);
    207   notifier.SetNow(schedule_time);
    208   notifier.Schedule();
    209   EXPECT_TRUE(notifier.HasPendingNotification());
    210 
    211   // Cancel the run.
    212   notifier.Cancel();
    213   EXPECT_FALSE(notifier.HasPendingNotification());
    214 
    215   std::deque<base::TestPendingTask> tasks = TakePendingTasks();
    216 
    217   ASSERT_EQ(1u, tasks.size());
    218   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    219 
    220   // Time to run, but a canceled task!
    221   tasks[0].task.Run();
    222   EXPECT_EQ(0, NotificationCount());
    223   EXPECT_FALSE(notifier.HasPendingNotification());
    224 
    225   tasks = TakePendingTasks();
    226   EXPECT_EQ(0u, tasks.size());
    227 
    228   notifier.Schedule();
    229   EXPECT_TRUE(notifier.HasPendingNotification());
    230   tasks = TakePendingTasks();
    231 
    232   ASSERT_EQ(1u, tasks.size());
    233   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    234 
    235   // Advance the time.
    236   notifier.SetNow(notifier.Now() + delay);
    237 
    238   // This should run since it wasn't canceled.
    239   tasks[0].task.Run();
    240   EXPECT_EQ(1, NotificationCount());
    241   EXPECT_FALSE(notifier.HasPendingNotification());
    242 
    243   for (int i = 0; i < 10; ++i) {
    244     notifier.Schedule();
    245     EXPECT_TRUE(notifier.HasPendingNotification());
    246     notifier.Cancel();
    247     EXPECT_FALSE(notifier.HasPendingNotification());
    248   }
    249 
    250   tasks = TakePendingTasks();
    251 
    252   ASSERT_EQ(1u, tasks.size());
    253   EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
    254 
    255   // Time to run, but a canceled task!
    256   notifier.SetNow(notifier.Now() + delay);
    257   tasks[0].task.Run();
    258   EXPECT_EQ(1, NotificationCount());
    259 
    260   tasks = TakePendingTasks();
    261   EXPECT_EQ(0u, tasks.size());
    262   EXPECT_FALSE(notifier.HasPendingNotification());
    263 }
    264 
    265 }  // namespace
    266 }  // namespace cc
    267