Home | History | Annotate | Download | only in notifier
      1 // Copyright (c) 2012 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 "sync/notifier/ack_tracker.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/memory/ref_counted.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/time/tick_clock.h"
     11 #include "google/cacheinvalidation/include/types.h"
     12 #include "google/cacheinvalidation/types.pb.h"
     13 #include "testing/gmock/include/gmock/gmock.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace syncer {
     17 
     18 namespace {
     19 
     20 class FakeTickClock : public base::TickClock {
     21  public:
     22   FakeTickClock() {}
     23 
     24   virtual ~FakeTickClock() {}
     25 
     26   void LeapForward(int seconds) {
     27     ASSERT_GT(seconds, 0);
     28     fake_now_ticks_ += base::TimeDelta::FromSeconds(seconds);
     29   }
     30 
     31   // After the next call to Now(), immediately leap forward by |seconds|.
     32   void DelayedLeapForward(int seconds) {
     33     ASSERT_GT(seconds, 0);
     34     delayed_leap_ = base::TimeDelta::FromSeconds(seconds);
     35   }
     36 
     37   virtual base::TimeTicks NowTicks() OVERRIDE {
     38     base::TimeTicks fake_now_ticks = fake_now_ticks_;
     39     if (delayed_leap_ > base::TimeDelta()) {
     40       fake_now_ticks_ += delayed_leap_;
     41       delayed_leap_ = base::TimeDelta();
     42     }
     43     return fake_now_ticks;
     44   }
     45 
     46  private:
     47   base::TimeTicks fake_now_ticks_;
     48   base::TimeDelta delayed_leap_;
     49 };
     50 
     51 class FakeBackoffEntry : public net::BackoffEntry {
     52  public:
     53   FakeBackoffEntry(const Policy* const policy, base::TickClock* tick_clock)
     54       : BackoffEntry(policy),
     55         tick_clock_(tick_clock) {
     56   }
     57 
     58  protected:
     59   virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE {
     60     return tick_clock_->NowTicks();
     61   }
     62 
     63  private:
     64   base::TickClock* const tick_clock_;
     65 };
     66 
     67 class MockDelegate : public AckTracker::Delegate {
     68  public:
     69   MOCK_METHOD1(OnTimeout, void(const ObjectIdSet&));
     70 };
     71 
     72 scoped_ptr<net::BackoffEntry> CreateMockEntry(
     73     base::TickClock* tick_clock,
     74     const net::BackoffEntry::Policy* const policy) {
     75   return scoped_ptr<net::BackoffEntry>(new FakeBackoffEntry(
     76       policy, tick_clock));
     77 }
     78 
     79 }  // namespace
     80 
     81 class AckTrackerTest : public testing::Test {
     82  public:
     83   AckTrackerTest()
     84       : ack_tracker_(&fake_tick_clock_, &delegate_),
     85         kIdOne(ipc::invalidation::ObjectSource::TEST, "one"),
     86         kIdTwo(ipc::invalidation::ObjectSource::TEST, "two") {
     87     ack_tracker_.SetCreateBackoffEntryCallbackForTest(
     88         base::Bind(&CreateMockEntry, &fake_tick_clock_));
     89   }
     90 
     91  protected:
     92   bool TriggerTimeoutNow() {
     93     return ack_tracker_.TriggerTimeoutAtForTest(fake_tick_clock_.NowTicks());
     94   }
     95 
     96   base::TimeDelta GetTimerDelay() const {
     97     const base::Timer& timer = ack_tracker_.GetTimerForTest();
     98     if (!timer.IsRunning())
     99       ADD_FAILURE() << "Timer is not running!";
    100     return timer.GetCurrentDelay();
    101   }
    102 
    103   FakeTickClock fake_tick_clock_;
    104   ::testing::StrictMock<MockDelegate> delegate_;
    105   AckTracker ack_tracker_;
    106 
    107   const invalidation::ObjectId kIdOne;
    108   const invalidation::ObjectId kIdTwo;
    109 
    110   // AckTracker uses base::Timer internally, which depends on the existence of a
    111   // MessageLoop.
    112   base::MessageLoop message_loop_;
    113 };
    114 
    115 // Tests that various combinations of Track()/Ack() behave as
    116 // expected.
    117 TEST_F(AckTrackerTest, TrackAndAck) {
    118   ObjectIdSet ids_one;
    119   ids_one.insert(kIdOne);
    120   ObjectIdSet ids_two;
    121   ids_two.insert(kIdTwo);
    122   ObjectIdSet ids_all;
    123   ids_all.insert(kIdOne);
    124   ids_all.insert(kIdTwo);
    125 
    126   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    127   ack_tracker_.Track(ids_one);
    128   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    129   ack_tracker_.Track(ids_two);
    130   ack_tracker_.Ack(ids_one);
    131   ack_tracker_.Ack(ids_two);
    132   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    133 
    134   ack_tracker_.Track(ids_all);
    135   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    136   ack_tracker_.Ack(ids_one);
    137   ack_tracker_.Ack(ids_two);
    138   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    139 
    140   ack_tracker_.Track(ids_one);
    141   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    142   ack_tracker_.Track(ids_two);
    143   ack_tracker_.Ack(ids_all);
    144   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    145 
    146   ack_tracker_.Track(ids_all);
    147   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    148   ack_tracker_.Ack(ids_all);
    149   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    150 }
    151 
    152 TEST_F(AckTrackerTest, DoubleTrack) {
    153   ObjectIdSet ids;
    154   ids.insert(kIdOne);
    155 
    156   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    157   ack_tracker_.Track(ids);
    158   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    159   ack_tracker_.Track(ids);
    160   ack_tracker_.Ack(ids);
    161   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    162 }
    163 
    164 TEST_F(AckTrackerTest, UntrackedAck) {
    165   ObjectIdSet ids;
    166   ids.insert(kIdOne);
    167 
    168   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    169   ack_tracker_.Ack(ids);
    170   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    171 }
    172 
    173 TEST_F(AckTrackerTest, Clear) {
    174   ObjectIdSet ids;
    175   ids.insert(kIdOne);
    176   ids.insert(kIdOne);
    177 
    178   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    179   ack_tracker_.Track(ids);
    180   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    181   ack_tracker_.Clear();
    182   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    183 }
    184 
    185 // Test that timeout behavior for one object ID. The timeout should increase
    186 // exponentially until it hits the cap.
    187 TEST_F(AckTrackerTest, SimpleTimeout) {
    188   ObjectIdSet ids;
    189   ids.insert(kIdOne);
    190 
    191   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    192   ack_tracker_.Track(ids);
    193   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    194 
    195   EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
    196   fake_tick_clock_.LeapForward(60);
    197   EXPECT_CALL(delegate_, OnTimeout(ids));
    198   EXPECT_TRUE(TriggerTimeoutNow());
    199 
    200   EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
    201   fake_tick_clock_.LeapForward(120);
    202   EXPECT_CALL(delegate_, OnTimeout(ids));
    203   EXPECT_TRUE(TriggerTimeoutNow());
    204 
    205   EXPECT_EQ(base::TimeDelta::FromSeconds(240), GetTimerDelay());
    206   fake_tick_clock_.LeapForward(240);
    207   EXPECT_CALL(delegate_, OnTimeout(ids));
    208   EXPECT_TRUE(TriggerTimeoutNow());
    209 
    210   EXPECT_EQ(base::TimeDelta::FromSeconds(480), GetTimerDelay());
    211   fake_tick_clock_.LeapForward(480);
    212   EXPECT_CALL(delegate_, OnTimeout(ids));
    213   EXPECT_TRUE(TriggerTimeoutNow());
    214 
    215   EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
    216   fake_tick_clock_.LeapForward(600);
    217   EXPECT_CALL(delegate_, OnTimeout(ids));
    218   EXPECT_TRUE(TriggerTimeoutNow());
    219 
    220   EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
    221   fake_tick_clock_.LeapForward(600);
    222   EXPECT_CALL(delegate_, OnTimeout(ids));
    223   EXPECT_TRUE(TriggerTimeoutNow());
    224 
    225   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    226   ack_tracker_.Ack(ids);
    227   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    228 
    229   // The backoff time should be reset after an Ack/Track cycle.
    230   ack_tracker_.Track(ids);
    231   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    232 
    233   EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
    234   fake_tick_clock_.LeapForward(60);
    235   EXPECT_CALL(delegate_, OnTimeout(ids));
    236   EXPECT_TRUE(TriggerTimeoutNow());
    237 
    238   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    239   ack_tracker_.Ack(ids);
    240   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    241 }
    242 
    243 // Tests that a sequence of Track() calls that results in interleaving
    244 // timeouts occurs as expected.
    245 TEST_F(AckTrackerTest, InterleavedTimeout) {
    246   ObjectIdSet ids_one;
    247   ids_one.insert(kIdOne);
    248   ObjectIdSet ids_two;
    249   ids_two.insert(kIdTwo);
    250 
    251   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    252   ack_tracker_.Track(ids_one);
    253   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    254 
    255   fake_tick_clock_.LeapForward(30);
    256   ack_tracker_.Track(ids_two);
    257   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    258 
    259   EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
    260   fake_tick_clock_.LeapForward(30);
    261   EXPECT_CALL(delegate_, OnTimeout(ids_one));
    262   EXPECT_TRUE(TriggerTimeoutNow());
    263 
    264   EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
    265   fake_tick_clock_.LeapForward(30);
    266   EXPECT_CALL(delegate_, OnTimeout(ids_two));
    267   EXPECT_TRUE(TriggerTimeoutNow());
    268 
    269   EXPECT_EQ(base::TimeDelta::FromSeconds(90), GetTimerDelay());
    270   fake_tick_clock_.LeapForward(90);
    271   EXPECT_CALL(delegate_, OnTimeout(ids_one));
    272   EXPECT_TRUE(TriggerTimeoutNow());
    273 
    274   EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
    275   fake_tick_clock_.LeapForward(30);
    276   EXPECT_CALL(delegate_, OnTimeout(ids_two));
    277   EXPECT_TRUE(TriggerTimeoutNow());
    278 
    279   ack_tracker_.Ack(ids_one);
    280   ack_tracker_.Ack(ids_two);
    281   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    282 }
    283 
    284 // Tests that registering a new object ID properly shortens the timeout when
    285 // needed.
    286 TEST_F(AckTrackerTest, ShortenTimeout) {
    287   ObjectIdSet ids_one;
    288   ids_one.insert(kIdOne);
    289   ObjectIdSet ids_two;
    290   ids_two.insert(kIdTwo);
    291 
    292   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    293   ack_tracker_.Track(ids_one);
    294   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    295 
    296   EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
    297   fake_tick_clock_.LeapForward(60);
    298   EXPECT_CALL(delegate_, OnTimeout(ids_one));
    299   EXPECT_TRUE(TriggerTimeoutNow());
    300 
    301   // Without this next register, the next timeout should occur in 120 seconds
    302   // from the last timeout event.
    303   EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
    304   fake_tick_clock_.LeapForward(30);
    305   ack_tracker_.Track(ids_two);
    306   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    307 
    308   // Now that we've registered another entry though, we should receive a timeout
    309   // in 60 seconds.
    310   EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
    311   fake_tick_clock_.LeapForward(60);
    312   EXPECT_CALL(delegate_, OnTimeout(ids_two));
    313   EXPECT_TRUE(TriggerTimeoutNow());
    314 
    315   // Verify that the original timeout for kIdOne still occurs as expected.
    316   EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
    317   fake_tick_clock_.LeapForward(30);
    318   EXPECT_CALL(delegate_, OnTimeout(ids_one));
    319   EXPECT_TRUE(TriggerTimeoutNow());
    320 
    321   ack_tracker_.Ack(ids_one);
    322   ack_tracker_.Ack(ids_two);
    323   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    324 }
    325 
    326 // Tests that a delay between inserting a new object ID registration and start
    327 // the timer that is greater than the initial timeout period (60 seconds) does
    328 // not break things. This could happen on a heavily loaded system, for instance.
    329 TEST_F(AckTrackerTest, ImmediateTimeout) {
    330   ObjectIdSet ids;
    331   ids.insert(kIdOne);
    332 
    333   fake_tick_clock_.DelayedLeapForward(90);
    334   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    335   ack_tracker_.Track(ids);
    336   EXPECT_FALSE(ack_tracker_.IsQueueEmptyForTest());
    337 
    338   EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimerDelay());
    339   EXPECT_CALL(delegate_, OnTimeout(ids));
    340   message_loop_.RunUntilIdle();
    341 
    342   // The next timeout should still be scheduled normally.
    343   EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
    344   fake_tick_clock_.LeapForward(120);
    345   EXPECT_CALL(delegate_, OnTimeout(ids));
    346   EXPECT_TRUE(TriggerTimeoutNow());
    347 
    348   ack_tracker_.Ack(ids);
    349   EXPECT_TRUE(ack_tracker_.IsQueueEmptyForTest());
    350 }
    351 
    352 }  // namespace syncer
    353