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