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/memory/ref_counted.h"
8 #include "base/message_loop.h"
9 #include "google/cacheinvalidation/include/types.h"
10 #include "google/cacheinvalidation/types.pb.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
18 typedef AckTracker::NowCallback NowCallback
;
20 class MockTimeProvider
: public base::RefCountedThreadSafe
<MockTimeProvider
> {
22 MockTimeProvider() : fake_now_(base::TimeTicks::Now()) {}
24 void LeapForward(int seconds
) {
25 ASSERT_GT(seconds
, 0);
26 fake_now_
+= base::TimeDelta::FromSeconds(seconds
);
29 // After the next call to Now(), immediately leap forward by |seconds|.
30 void DelayedLeapForward(int seconds
) {
31 ASSERT_GT(seconds
, 0);
32 delayed_leap_
= base::TimeDelta::FromSeconds(seconds
);
35 base::TimeTicks
Now() {
36 base::TimeTicks fake_now
= fake_now_
;
37 if (delayed_leap_
> base::TimeDelta()) {
38 fake_now_
+= delayed_leap_
;
39 delayed_leap_
= base::TimeDelta();
45 friend class base::RefCountedThreadSafe
<MockTimeProvider
>;
47 ~MockTimeProvider() {}
49 base::TimeTicks fake_now_
;
50 base::TimeDelta delayed_leap_
;
53 class FakeBackoffEntry
: public net::BackoffEntry
{
55 FakeBackoffEntry(const Policy
* const policy
, const NowCallback
& now_callback
)
56 : BackoffEntry(policy
),
57 now_callback_(now_callback
) {
61 virtual base::TimeTicks
ImplGetTimeNow() const OVERRIDE
{
62 return now_callback_
.Run();
66 NowCallback now_callback_
;
69 class MockDelegate
: public AckTracker::Delegate
{
71 MOCK_METHOD1(OnTimeout
, void(const ObjectIdSet
&));
74 scoped_ptr
<net::BackoffEntry
> CreateMockEntry(
75 const NowCallback
& now_callback
,
76 const net::BackoffEntry::Policy
* const policy
) {
77 return scoped_ptr
<net::BackoffEntry
>(new FakeBackoffEntry(
78 policy
, now_callback
));
83 class AckTrackerTest
: public testing::Test
{
86 : time_provider_(new MockTimeProvider
),
87 ack_tracker_(&delegate_
),
88 kIdOne(ipc::invalidation::ObjectSource::TEST
, "one"),
89 kIdTwo(ipc::invalidation::ObjectSource::TEST
, "two") {
90 ack_tracker_
.SetNowCallbackForTest(
91 base::Bind(&MockTimeProvider::Now
, time_provider_
));
92 ack_tracker_
.SetCreateBackoffEntryCallbackForTest(
93 base::Bind(&CreateMockEntry
,
94 base::Bind(&MockTimeProvider::Now
,
99 bool TriggerTimeoutNow() {
100 return ack_tracker_
.TriggerTimeoutAtForTest(time_provider_
->Now());
103 base::TimeDelta
GetTimerDelay() const {
104 const base::Timer
& timer
= ack_tracker_
.GetTimerForTest();
105 if (!timer
.IsRunning())
106 ADD_FAILURE() << "Timer is not running!";
107 return timer
.GetCurrentDelay();
110 scoped_refptr
<MockTimeProvider
> time_provider_
;
111 ::testing::StrictMock
<MockDelegate
> delegate_
;
112 AckTracker ack_tracker_
;
114 const invalidation::ObjectId kIdOne
;
115 const invalidation::ObjectId kIdTwo
;
117 // AckTracker uses base::Timer internally, which depends on the existence of a
119 MessageLoop message_loop_
;
122 // Tests that various combinations of Track()/Ack() behave as
124 TEST_F(AckTrackerTest
, TrackAndAck
) {
126 ids_one
.insert(kIdOne
);
128 ids_two
.insert(kIdTwo
);
130 ids_all
.insert(kIdOne
);
131 ids_all
.insert(kIdTwo
);
133 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
134 ack_tracker_
.Track(ids_one
);
135 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
136 ack_tracker_
.Track(ids_two
);
137 ack_tracker_
.Ack(ids_one
);
138 ack_tracker_
.Ack(ids_two
);
139 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
141 ack_tracker_
.Track(ids_all
);
142 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
143 ack_tracker_
.Ack(ids_one
);
144 ack_tracker_
.Ack(ids_two
);
145 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
147 ack_tracker_
.Track(ids_one
);
148 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
149 ack_tracker_
.Track(ids_two
);
150 ack_tracker_
.Ack(ids_all
);
151 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
153 ack_tracker_
.Track(ids_all
);
154 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
155 ack_tracker_
.Ack(ids_all
);
156 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
159 TEST_F(AckTrackerTest
, DoubleTrack
) {
163 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
164 ack_tracker_
.Track(ids
);
165 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
166 ack_tracker_
.Track(ids
);
167 ack_tracker_
.Ack(ids
);
168 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
171 TEST_F(AckTrackerTest
, UntrackedAck
) {
175 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
176 ack_tracker_
.Ack(ids
);
177 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
180 TEST_F(AckTrackerTest
, Clear
) {
185 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
186 ack_tracker_
.Track(ids
);
187 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
188 ack_tracker_
.Clear();
189 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
192 // Test that timeout behavior for one object ID. The timeout should increase
193 // exponentially until it hits the cap.
194 TEST_F(AckTrackerTest
, SimpleTimeout
) {
198 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
199 ack_tracker_
.Track(ids
);
200 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
202 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
203 time_provider_
->LeapForward(60);
204 EXPECT_CALL(delegate_
, OnTimeout(ids
));
205 EXPECT_TRUE(TriggerTimeoutNow());
207 EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
208 time_provider_
->LeapForward(120);
209 EXPECT_CALL(delegate_
, OnTimeout(ids
));
210 EXPECT_TRUE(TriggerTimeoutNow());
212 EXPECT_EQ(base::TimeDelta::FromSeconds(240), GetTimerDelay());
213 time_provider_
->LeapForward(240);
214 EXPECT_CALL(delegate_
, OnTimeout(ids
));
215 EXPECT_TRUE(TriggerTimeoutNow());
217 EXPECT_EQ(base::TimeDelta::FromSeconds(480), GetTimerDelay());
218 time_provider_
->LeapForward(480);
219 EXPECT_CALL(delegate_
, OnTimeout(ids
));
220 EXPECT_TRUE(TriggerTimeoutNow());
222 EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
223 time_provider_
->LeapForward(600);
224 EXPECT_CALL(delegate_
, OnTimeout(ids
));
225 EXPECT_TRUE(TriggerTimeoutNow());
227 EXPECT_EQ(base::TimeDelta::FromSeconds(600), GetTimerDelay());
228 time_provider_
->LeapForward(600);
229 EXPECT_CALL(delegate_
, OnTimeout(ids
));
230 EXPECT_TRUE(TriggerTimeoutNow());
232 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
233 ack_tracker_
.Ack(ids
);
234 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
236 // The backoff time should be reset after an Ack/Track cycle.
237 ack_tracker_
.Track(ids
);
238 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
240 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
241 time_provider_
->LeapForward(60);
242 EXPECT_CALL(delegate_
, OnTimeout(ids
));
243 EXPECT_TRUE(TriggerTimeoutNow());
245 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
246 ack_tracker_
.Ack(ids
);
247 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
250 // Tests that a sequence of Track() calls that results in interleaving
251 // timeouts occurs as expected.
252 TEST_F(AckTrackerTest
, InterleavedTimeout
) {
254 ids_one
.insert(kIdOne
);
256 ids_two
.insert(kIdTwo
);
258 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
259 ack_tracker_
.Track(ids_one
);
260 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
262 time_provider_
->LeapForward(30);
263 ack_tracker_
.Track(ids_two
);
264 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
266 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
267 time_provider_
->LeapForward(30);
268 EXPECT_CALL(delegate_
, OnTimeout(ids_one
));
269 EXPECT_TRUE(TriggerTimeoutNow());
271 EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
272 time_provider_
->LeapForward(30);
273 EXPECT_CALL(delegate_
, OnTimeout(ids_two
));
274 EXPECT_TRUE(TriggerTimeoutNow());
276 EXPECT_EQ(base::TimeDelta::FromSeconds(90), GetTimerDelay());
277 time_provider_
->LeapForward(90);
278 EXPECT_CALL(delegate_
, OnTimeout(ids_one
));
279 EXPECT_TRUE(TriggerTimeoutNow());
281 EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
282 time_provider_
->LeapForward(30);
283 EXPECT_CALL(delegate_
, OnTimeout(ids_two
));
284 EXPECT_TRUE(TriggerTimeoutNow());
286 ack_tracker_
.Ack(ids_one
);
287 ack_tracker_
.Ack(ids_two
);
288 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
291 // Tests that registering a new object ID properly shortens the timeout when
293 TEST_F(AckTrackerTest
, ShortenTimeout
) {
295 ids_one
.insert(kIdOne
);
297 ids_two
.insert(kIdTwo
);
299 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
300 ack_tracker_
.Track(ids_one
);
301 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
303 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
304 time_provider_
->LeapForward(60);
305 EXPECT_CALL(delegate_
, OnTimeout(ids_one
));
306 EXPECT_TRUE(TriggerTimeoutNow());
308 // Without this next register, the next timeout should occur in 120 seconds
309 // from the last timeout event.
310 EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
311 time_provider_
->LeapForward(30);
312 ack_tracker_
.Track(ids_two
);
313 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
315 // Now that we've registered another entry though, we should receive a timeout
317 EXPECT_EQ(base::TimeDelta::FromSeconds(60), GetTimerDelay());
318 time_provider_
->LeapForward(60);
319 EXPECT_CALL(delegate_
, OnTimeout(ids_two
));
320 EXPECT_TRUE(TriggerTimeoutNow());
322 // Verify that the original timeout for kIdOne still occurs as expected.
323 EXPECT_EQ(base::TimeDelta::FromSeconds(30), GetTimerDelay());
324 time_provider_
->LeapForward(30);
325 EXPECT_CALL(delegate_
, OnTimeout(ids_one
));
326 EXPECT_TRUE(TriggerTimeoutNow());
328 ack_tracker_
.Ack(ids_one
);
329 ack_tracker_
.Ack(ids_two
);
330 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
333 // Tests that a delay between inserting a new object ID registration and start
334 // the timer that is greater than the initial timeout period (60 seconds) does
335 // not break things. This could happen on a heavily loaded system, for instance.
336 TEST_F(AckTrackerTest
, ImmediateTimeout
) {
340 time_provider_
->DelayedLeapForward(90);
341 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
342 ack_tracker_
.Track(ids
);
343 EXPECT_FALSE(ack_tracker_
.IsQueueEmptyForTest());
345 EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimerDelay());
346 EXPECT_CALL(delegate_
, OnTimeout(ids
));
347 message_loop_
.RunUntilIdle();
349 // The next timeout should still be scheduled normally.
350 EXPECT_EQ(base::TimeDelta::FromSeconds(120), GetTimerDelay());
351 time_provider_
->LeapForward(120);
352 EXPECT_CALL(delegate_
, OnTimeout(ids
));
353 EXPECT_TRUE(TriggerTimeoutNow());
355 ack_tracker_
.Ack(ids
);
356 EXPECT_TRUE(ack_tracker_
.IsQueueEmptyForTest());
359 } // namespace syncer