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.
5 #include "sync/notifier/ack_tracker.h"
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"
20 class FakeTickClock
: public base::TickClock
{
24 virtual ~FakeTickClock() {}
26 void LeapForward(int seconds
) {
27 ASSERT_GT(seconds
, 0);
28 fake_now_ticks_
+= base::TimeDelta::FromSeconds(seconds
);
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
);
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();
43 return fake_now_ticks
;
47 base::TimeTicks fake_now_ticks_
;
48 base::TimeDelta delayed_leap_
;
51 class FakeBackoffEntry
: public net::BackoffEntry
{
53 FakeBackoffEntry(const Policy
* const policy
, base::TickClock
* tick_clock
)
54 : BackoffEntry(policy
),
55 tick_clock_(tick_clock
) {
59 virtual base::TimeTicks
ImplGetTimeNow() const OVERRIDE
{
60 return tick_clock_
->NowTicks();
64 base::TickClock
* const tick_clock_
;
67 class MockDelegate
: public AckTracker::Delegate
{
69 MOCK_METHOD1(OnTimeout
, void(const ObjectIdSet
&));
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(
81 class AckTrackerTest
: public testing::Test
{
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_
));
92 bool TriggerTimeoutNow() {
93 return ack_tracker_
.TriggerTimeoutAtForTest(fake_tick_clock_
.NowTicks());
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();
103 FakeTickClock fake_tick_clock_
;
104 ::testing::StrictMock
<MockDelegate
> delegate_
;
105 AckTracker ack_tracker_
;
107 const invalidation::ObjectId kIdOne
;
108 const invalidation::ObjectId kIdTwo
;
110 // AckTracker uses base::Timer internally, which depends on the existence of a
112 base::MessageLoop message_loop_
;
115 // Tests that various combinations of Track()/Ack() behave as
117 TEST_F(AckTrackerTest
, TrackAndAck
) {
119 ids_one
.insert(kIdOne
);
121 ids_two
.insert(kIdTwo
);
123 ids_all
.insert(kIdOne
);
124 ids_all
.insert(kIdTwo
);
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());
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());
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());
146 ack_tracker_
.Track(ids_all
);
147 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
148 ack_tracker_
.Ack(ids_all
);
149 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
152 TEST_F(AckTrackerTest
, DoubleTrack
) {
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());
164 TEST_F(AckTrackerTest
, UntrackedAck
) {
168 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
169 ack_tracker_
.Ack(ids
);
170 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
173 TEST_F(AckTrackerTest
, Clear
) {
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());
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
) {
191 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
192 ack_tracker_
.Track(ids
);
193 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
195 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
196 fake_tick_clock_
.LeapForward(60);
197 EXPECT_CALL(delegate_
, OnTimeout(ids
));
198 EXPECT_TRUE(TriggerTimeoutNow());
200 EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
201 fake_tick_clock_
.LeapForward(120);
202 EXPECT_CALL(delegate_
, OnTimeout(ids
));
203 EXPECT_TRUE(TriggerTimeoutNow());
205 EXPECT_EQ(base::TimeDelta::FromSeconds(240), GetTimerDelay());
206 fake_tick_clock_
.LeapForward(240);
207 EXPECT_CALL(delegate_
, OnTimeout(ids
));
208 EXPECT_TRUE(TriggerTimeoutNow());
210 EXPECT_EQ(base::TimeDelta::FromSeconds(480), GetTimerDelay());
211 fake_tick_clock_
.LeapForward(480);
212 EXPECT_CALL(delegate_
, OnTimeout(ids
));
213 EXPECT_TRUE(TriggerTimeoutNow());
215 EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
216 fake_tick_clock_
.LeapForward(600);
217 EXPECT_CALL(delegate_
, OnTimeout(ids
));
218 EXPECT_TRUE(TriggerTimeoutNow());
220 EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
221 fake_tick_clock_
.LeapForward(600);
222 EXPECT_CALL(delegate_
, OnTimeout(ids
));
223 EXPECT_TRUE(TriggerTimeoutNow());
225 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
226 ack_tracker_
.Ack(ids
);
227 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
229 // The backoff time should be reset after an Ack/Track cycle.
230 ack_tracker_
.Track(ids
);
231 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
233 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
234 fake_tick_clock_
.LeapForward(60);
235 EXPECT_CALL(delegate_
, OnTimeout(ids
));
236 EXPECT_TRUE(TriggerTimeoutNow());
238 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
239 ack_tracker_
.Ack(ids
);
240 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
243 // Tests that a sequence of Track() calls that results in interleaving
244 // timeouts occurs as expected.
245 TEST_F(AckTrackerTest
, InterleavedTimeout
) {
247 ids_one
.insert(kIdOne
);
249 ids_two
.insert(kIdTwo
);
251 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
252 ack_tracker_
.Track(ids_one
);
253 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
255 fake_tick_clock_
.LeapForward(30);
256 ack_tracker_
.Track(ids_two
);
257 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
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());
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());
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());
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());
279 ack_tracker_
.Ack(ids_one
);
280 ack_tracker_
.Ack(ids_two
);
281 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
284 // Tests that registering a new object ID properly shortens the timeout when
286 TEST_F(AckTrackerTest
, ShortenTimeout
) {
288 ids_one
.insert(kIdOne
);
290 ids_two
.insert(kIdTwo
);
292 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
293 ack_tracker_
.Track(ids_one
);
294 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
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());
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());
308 // Now that we've registered another entry though, we should receive a timeout
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());
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());
321 ack_tracker_
.Ack(ids_one
);
322 ack_tracker_
.Ack(ids_two
);
323 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
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
) {
333 fake_tick_clock_
.DelayedLeapForward(90);
334 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
335 ack_tracker_
.Track(ids
);
336 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
338 EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimerDelay());
339 EXPECT_CALL(delegate_
, OnTimeout(ids
));
340 message_loop_
.RunUntilIdle();
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());
348 ack_tracker_
.Ack(ids
);
349 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
352 } // namespace syncer