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 "base/message_loop/message_loop.h"
6 #include "base/run_loop.h"
7 #include "sync/internal_api/public/base/model_type_test_util.h"
8 #include "sync/sessions/nudge_tracker.h"
9 #include "sync/test/mock_invalidation.h"
10 #include "sync/test/mock_invalidation_tracker.h"
11 #include "sync/test/trackable_mock_invalidation.h"
12 #include "testing/gtest/include/gtest/gtest.h"
18 testing::AssertionResult
ModelTypeSetEquals(ModelTypeSet a
, ModelTypeSet b
) {
20 return testing::AssertionSuccess();
22 return testing::AssertionFailure()
23 << "Left side " << ModelTypeSetToString(a
)
24 << ", does not match rigth side: " << ModelTypeSetToString(b
);
32 class NudgeTrackerTest
: public ::testing::Test
{
35 SetInvalidationsInSync();
38 static size_t GetHintBufferSize() {
39 // Assumes that no test has adjusted this size.
40 return NudgeTracker::kDefaultMaxPayloadsPerType
;
43 bool InvalidationsOutOfSync() const {
44 // We don't currently track invalidations out of sync on a per-type basis.
45 sync_pb::GetUpdateTriggers gu_trigger
;
46 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
47 return gu_trigger
.invalidations_out_of_sync();
50 int ProtoLocallyModifiedCount(ModelType type
) const {
51 sync_pb::GetUpdateTriggers gu_trigger
;
52 nudge_tracker_
.FillProtoMessage(type
, &gu_trigger
);
53 return gu_trigger
.local_modification_nudges();
56 int ProtoRefreshRequestedCount(ModelType type
) const {
57 sync_pb::GetUpdateTriggers gu_trigger
;
58 nudge_tracker_
.FillProtoMessage(type
, &gu_trigger
);
59 return gu_trigger
.datatype_refresh_nudges();
62 void SetInvalidationsInSync() {
63 nudge_tracker_
.OnInvalidationsEnabled();
64 nudge_tracker_
.RecordSuccessfulSyncCycle();
67 scoped_ptr
<InvalidationInterface
> BuildInvalidation(
69 const std::string
& payload
) {
70 return MockInvalidation::Build(version
, payload
)
71 .PassAs
<InvalidationInterface
>();
74 static scoped_ptr
<InvalidationInterface
> BuildUnknownVersionInvalidation() {
75 return MockInvalidation::BuildUnknownVersion()
76 .PassAs
<InvalidationInterface
>();
80 NudgeTracker nudge_tracker_
;
83 // Exercise an empty NudgeTracker.
84 // Use with valgrind to detect uninitialized members.
85 TEST_F(NudgeTrackerTest
, EmptyNudgeTracker
) {
86 // Now we're at the normal, "idle" state.
87 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
88 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
89 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN
,
90 nudge_tracker_
.GetLegacySource());
92 sync_pb::GetUpdateTriggers gu_trigger
;
93 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
95 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN
,
96 nudge_tracker_
.GetLegacySource());
99 // Verify that nudges override each other based on a priority order.
100 // RETRY < LOCAL < DATATYPE_REFRESH < NOTIFICATION
101 TEST_F(NudgeTrackerTest
, SourcePriorities
) {
102 // Start with a retry request.
103 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(1234);
104 const base::TimeTicks t1
= t0
+ base::TimeDelta::FromSeconds(10);
105 nudge_tracker_
.SetNextRetryTime(t0
);
106 nudge_tracker_
.SetSyncCycleStartTime(t1
);
107 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY
,
108 nudge_tracker_
.GetLegacySource());
110 // Track a local nudge.
111 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
112 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL
,
113 nudge_tracker_
.GetLegacySource());
115 // A refresh request will override it.
116 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS
));
117 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH
,
118 nudge_tracker_
.GetLegacySource());
120 // Another local nudge will not be enough to change it.
121 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
122 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH
,
123 nudge_tracker_
.GetLegacySource());
125 // An invalidation will override the refresh request source.
126 nudge_tracker_
.RecordRemoteInvalidation(PREFERENCES
,
127 BuildInvalidation(1, "hint"));
128 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION
,
129 nudge_tracker_
.GetLegacySource());
131 // Neither local nudges nor refresh requests will override it.
132 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
133 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION
,
134 nudge_tracker_
.GetLegacySource());
135 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS
));
136 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION
,
137 nudge_tracker_
.GetLegacySource());
140 TEST_F(NudgeTrackerTest
, SourcePriority_InitialSyncRequest
) {
141 nudge_tracker_
.RecordInitialSyncRequired(BOOKMARKS
);
143 // For lack of a better source, we describe an initial sync request as having
144 // source DATATYPE_REFRESH.
145 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH
,
146 nudge_tracker_
.GetLegacySource());
148 // This should never happen in practice. But, if it did, we'd want the
149 // initial sync required to keep the source set to DATATYPE_REFRESH.
150 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
151 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH
,
152 nudge_tracker_
.GetLegacySource());
154 // It should be safe to let NOTIFICATIONs override it.
155 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
156 BuildInvalidation(1, "hint"));
157 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION
,
158 nudge_tracker_
.GetLegacySource());
161 // Verifies the management of invalidation hints and GU trigger fields.
162 TEST_F(NudgeTrackerTest
, HintCoalescing
) {
163 // Easy case: record one hint.
165 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
166 BuildInvalidation(1, "bm_hint_1"));
168 sync_pb::GetUpdateTriggers gu_trigger
;
169 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
170 ASSERT_EQ(1, gu_trigger
.notification_hint_size());
171 EXPECT_EQ("bm_hint_1", gu_trigger
.notification_hint(0));
172 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
175 // Record a second hint for the same type.
177 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
178 BuildInvalidation(2, "bm_hint_2"));
180 sync_pb::GetUpdateTriggers gu_trigger
;
181 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
182 ASSERT_EQ(2, gu_trigger
.notification_hint_size());
184 // Expect the most hint recent is last in the list.
185 EXPECT_EQ("bm_hint_1", gu_trigger
.notification_hint(0));
186 EXPECT_EQ("bm_hint_2", gu_trigger
.notification_hint(1));
187 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
190 // Record a hint for a different type.
192 nudge_tracker_
.RecordRemoteInvalidation(PASSWORDS
,
193 BuildInvalidation(1, "pw_hint_1"));
195 // Re-verify the bookmarks to make sure they're unaffected.
196 sync_pb::GetUpdateTriggers bm_gu_trigger
;
197 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &bm_gu_trigger
);
198 ASSERT_EQ(2, bm_gu_trigger
.notification_hint_size());
199 EXPECT_EQ("bm_hint_1", bm_gu_trigger
.notification_hint(0));
200 EXPECT_EQ("bm_hint_2",
201 bm_gu_trigger
.notification_hint(1)); // most recent last.
202 EXPECT_FALSE(bm_gu_trigger
.client_dropped_hints());
204 // Verify the new type, too.
205 sync_pb::GetUpdateTriggers pw_gu_trigger
;
206 nudge_tracker_
.FillProtoMessage(PASSWORDS
, &pw_gu_trigger
);
207 ASSERT_EQ(1, pw_gu_trigger
.notification_hint_size());
208 EXPECT_EQ("pw_hint_1", pw_gu_trigger
.notification_hint(0));
209 EXPECT_FALSE(pw_gu_trigger
.client_dropped_hints());
213 // Test the dropping of invalidation hints. Receives invalidations one by one.
214 TEST_F(NudgeTrackerTest
, DropHintsLocally_OneAtATime
) {
215 for (size_t i
= 0; i
< GetHintBufferSize(); ++i
) {
216 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
217 BuildInvalidation(i
, "hint"));
220 sync_pb::GetUpdateTriggers gu_trigger
;
221 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
222 EXPECT_EQ(GetHintBufferSize(),
223 static_cast<size_t>(gu_trigger
.notification_hint_size()));
224 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
227 // Force an overflow.
228 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
229 BuildInvalidation(1000, "new_hint"));
232 sync_pb::GetUpdateTriggers gu_trigger
;
233 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
234 EXPECT_TRUE(gu_trigger
.client_dropped_hints());
235 ASSERT_EQ(GetHintBufferSize(),
236 static_cast<size_t>(gu_trigger
.notification_hint_size()));
238 // Verify the newest hint was not dropped and is the last in the list.
239 EXPECT_EQ("new_hint", gu_trigger
.notification_hint(GetHintBufferSize()-1));
241 // Verify the oldest hint, too.
242 EXPECT_EQ("hint", gu_trigger
.notification_hint(0));
246 // Tests the receipt of 'unknown version' invalidations.
247 TEST_F(NudgeTrackerTest
, DropHintsAtServer_Alone
) {
248 // Record the unknown version invalidation.
249 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
250 BuildUnknownVersionInvalidation());
252 sync_pb::GetUpdateTriggers gu_trigger
;
253 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
254 EXPECT_TRUE(gu_trigger
.server_dropped_hints());
255 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
256 ASSERT_EQ(0, gu_trigger
.notification_hint_size());
259 // Clear status then verify.
260 nudge_tracker_
.RecordSuccessfulSyncCycle();
262 sync_pb::GetUpdateTriggers gu_trigger
;
263 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
264 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
265 EXPECT_FALSE(gu_trigger
.server_dropped_hints());
266 ASSERT_EQ(0, gu_trigger
.notification_hint_size());
270 // Tests the receipt of 'unknown version' invalidations. This test also
271 // includes a known version invalidation to mix things up a bit.
272 TEST_F(NudgeTrackerTest
, DropHintsAtServer_WithOtherInvalidations
) {
273 // Record the two invalidations, one with unknown version, the other known.
274 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
275 BuildUnknownVersionInvalidation());
276 nudge_tracker_
.RecordRemoteInvalidation(BOOKMARKS
,
277 BuildInvalidation(10, "hint"));
280 sync_pb::GetUpdateTriggers gu_trigger
;
281 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
282 EXPECT_TRUE(gu_trigger
.server_dropped_hints());
283 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
284 ASSERT_EQ(1, gu_trigger
.notification_hint_size());
285 EXPECT_EQ("hint", gu_trigger
.notification_hint(0));
288 // Clear status then verify.
289 nudge_tracker_
.RecordSuccessfulSyncCycle();
291 sync_pb::GetUpdateTriggers gu_trigger
;
292 nudge_tracker_
.FillProtoMessage(BOOKMARKS
, &gu_trigger
);
293 EXPECT_FALSE(gu_trigger
.client_dropped_hints());
294 EXPECT_FALSE(gu_trigger
.server_dropped_hints());
295 ASSERT_EQ(0, gu_trigger
.notification_hint_size());
299 // Checks the behaviour of the invalidations-out-of-sync flag.
300 TEST_F(NudgeTrackerTest
, EnableDisableInvalidations
) {
301 // Start with invalidations offline.
302 nudge_tracker_
.OnInvalidationsDisabled();
303 EXPECT_TRUE(InvalidationsOutOfSync());
304 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
306 // Simply enabling invalidations does not bring us back into sync.
307 nudge_tracker_
.OnInvalidationsEnabled();
308 EXPECT_TRUE(InvalidationsOutOfSync());
309 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
311 // We must successfully complete a sync cycle while invalidations are enabled
312 // to be sure that we're in sync.
313 nudge_tracker_
.RecordSuccessfulSyncCycle();
314 EXPECT_FALSE(InvalidationsOutOfSync());
315 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
317 // If the invalidator malfunctions, we go become unsynced again.
318 nudge_tracker_
.OnInvalidationsDisabled();
319 EXPECT_TRUE(InvalidationsOutOfSync());
320 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
322 // A sync cycle while invalidations are disabled won't reset the flag.
323 nudge_tracker_
.RecordSuccessfulSyncCycle();
324 EXPECT_TRUE(InvalidationsOutOfSync());
325 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
327 // Nor will the re-enabling of invalidations be sufficient, even now that
328 // we've had a successful sync cycle.
329 nudge_tracker_
.RecordSuccessfulSyncCycle();
330 EXPECT_TRUE(InvalidationsOutOfSync());
331 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
334 // Tests that locally modified types are correctly written out to the
335 // GetUpdateTriggers proto.
336 TEST_F(NudgeTrackerTest
, WriteLocallyModifiedTypesToProto
) {
337 // Should not be locally modified by default.
338 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES
));
340 // Record a local bookmark change. Verify it was registered correctly.
341 nudge_tracker_
.RecordLocalChange(ModelTypeSet(PREFERENCES
));
342 EXPECT_EQ(1, ProtoLocallyModifiedCount(PREFERENCES
));
344 // Record a successful sync cycle. Verify the count is cleared.
345 nudge_tracker_
.RecordSuccessfulSyncCycle();
346 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES
));
349 // Tests that refresh requested types are correctly written out to the
350 // GetUpdateTriggers proto.
351 TEST_F(NudgeTrackerTest
, WriteRefreshRequestedTypesToProto
) {
352 // There should be no refresh requested by default.
353 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS
));
355 // Record a local refresh request. Verify it was registered correctly.
356 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS
));
357 EXPECT_EQ(1, ProtoRefreshRequestedCount(SESSIONS
));
359 // Record a successful sync cycle. Verify the count is cleared.
360 nudge_tracker_
.RecordSuccessfulSyncCycle();
361 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS
));
364 // Basic tests for the IsSyncRequired() flag.
365 TEST_F(NudgeTrackerTest
, IsSyncRequired
) {
366 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
368 // Initial sync request.
369 nudge_tracker_
.RecordInitialSyncRequired(BOOKMARKS
);
370 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
371 nudge_tracker_
.RecordSuccessfulSyncCycle();
372 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
375 nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
));
376 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
377 nudge_tracker_
.RecordSuccessfulSyncCycle();
378 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
381 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS
));
382 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
383 nudge_tracker_
.RecordSuccessfulSyncCycle();
384 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
387 nudge_tracker_
.RecordRemoteInvalidation(PREFERENCES
,
388 BuildInvalidation(1, "hint"));
389 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
390 nudge_tracker_
.RecordSuccessfulSyncCycle();
391 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
394 // Basic tests for the IsGetUpdatesRequired() flag.
395 TEST_F(NudgeTrackerTest
, IsGetUpdatesRequired
) {
396 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
398 // Initial sync request.
399 nudge_tracker_
.RecordInitialSyncRequired(BOOKMARKS
);
400 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
401 nudge_tracker_
.RecordSuccessfulSyncCycle();
402 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
405 nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
));
406 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
407 nudge_tracker_
.RecordSuccessfulSyncCycle();
408 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
411 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS
));
412 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
413 nudge_tracker_
.RecordSuccessfulSyncCycle();
414 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
417 nudge_tracker_
.RecordRemoteInvalidation(PREFERENCES
,
418 BuildInvalidation(1, "hint"));
419 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
420 nudge_tracker_
.RecordSuccessfulSyncCycle();
421 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
424 // Test IsSyncRequired() responds correctly to data type throttling.
425 TEST_F(NudgeTrackerTest
, IsSyncRequired_Throttling
) {
426 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(1234);
427 const base::TimeDelta throttle_length
= base::TimeDelta::FromMinutes(10);
428 const base::TimeTicks t1
= t0
+ throttle_length
;
430 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
432 // A local change to sessions enables the flag.
433 nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
));
434 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
436 // But the throttling of sessions unsets it.
437 nudge_tracker_
.SetTypesThrottledUntil(ModelTypeSet(SESSIONS
),
440 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
442 // A refresh request for bookmarks means we have reason to sync again.
443 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS
));
444 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
446 // A successful sync cycle means we took care of bookmarks.
447 nudge_tracker_
.RecordSuccessfulSyncCycle();
448 EXPECT_FALSE(nudge_tracker_
.IsSyncRequired());
450 // But we still haven't dealt with sessions. We'll need to remember
451 // that sessions are out of sync and re-enable the flag when their
452 // throttling interval expires.
453 nudge_tracker_
.UpdateTypeThrottlingState(t1
);
454 EXPECT_FALSE(nudge_tracker_
.IsTypeThrottled(SESSIONS
));
455 EXPECT_TRUE(nudge_tracker_
.IsSyncRequired());
458 // Test IsGetUpdatesRequired() responds correctly to data type throttling.
459 TEST_F(NudgeTrackerTest
, IsGetUpdatesRequired_Throttling
) {
460 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(1234);
461 const base::TimeDelta throttle_length
= base::TimeDelta::FromMinutes(10);
462 const base::TimeTicks t1
= t0
+ throttle_length
;
464 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
466 // A refresh request to sessions enables the flag.
467 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS
));
468 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
470 // But the throttling of sessions unsets it.
471 nudge_tracker_
.SetTypesThrottledUntil(ModelTypeSet(SESSIONS
),
474 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
476 // A refresh request for bookmarks means we have reason to sync again.
477 nudge_tracker_
.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS
));
478 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
480 // A successful sync cycle means we took care of bookmarks.
481 nudge_tracker_
.RecordSuccessfulSyncCycle();
482 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
484 // But we still haven't dealt with sessions. We'll need to remember
485 // that sessions are out of sync and re-enable the flag when their
486 // throttling interval expires.
487 nudge_tracker_
.UpdateTypeThrottlingState(t1
);
488 EXPECT_FALSE(nudge_tracker_
.IsTypeThrottled(SESSIONS
));
489 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
492 // Tests throttling-related getter functions when no types are throttled.
493 TEST_F(NudgeTrackerTest
, NoTypesThrottled
) {
494 EXPECT_FALSE(nudge_tracker_
.IsAnyTypeThrottled());
495 EXPECT_FALSE(nudge_tracker_
.IsTypeThrottled(SESSIONS
));
496 EXPECT_TRUE(nudge_tracker_
.GetThrottledTypes().Empty());
499 // Tests throttling-related getter functions when some types are throttled.
500 TEST_F(NudgeTrackerTest
, ThrottleAndUnthrottle
) {
501 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(1234);
502 const base::TimeDelta throttle_length
= base::TimeDelta::FromMinutes(10);
503 const base::TimeTicks t1
= t0
+ throttle_length
;
505 nudge_tracker_
.SetTypesThrottledUntil(ModelTypeSet(SESSIONS
, PREFERENCES
),
509 EXPECT_TRUE(nudge_tracker_
.IsAnyTypeThrottled());
510 EXPECT_TRUE(nudge_tracker_
.IsTypeThrottled(SESSIONS
));
511 EXPECT_TRUE(nudge_tracker_
.IsTypeThrottled(PREFERENCES
));
512 EXPECT_FALSE(nudge_tracker_
.GetThrottledTypes().Empty());
513 EXPECT_EQ(throttle_length
, nudge_tracker_
.GetTimeUntilNextUnthrottle(t0
));
515 nudge_tracker_
.UpdateTypeThrottlingState(t1
);
517 EXPECT_FALSE(nudge_tracker_
.IsAnyTypeThrottled());
518 EXPECT_FALSE(nudge_tracker_
.IsTypeThrottled(SESSIONS
));
519 EXPECT_TRUE(nudge_tracker_
.GetThrottledTypes().Empty());
522 TEST_F(NudgeTrackerTest
, OverlappingThrottleIntervals
) {
523 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(1234);
524 const base::TimeDelta throttle1_length
= base::TimeDelta::FromMinutes(10);
525 const base::TimeDelta throttle2_length
= base::TimeDelta::FromMinutes(20);
526 const base::TimeTicks t1
= t0
+ throttle1_length
;
527 const base::TimeTicks t2
= t0
+ throttle2_length
;
529 // Setup the longer of two intervals.
530 nudge_tracker_
.SetTypesThrottledUntil(ModelTypeSet(SESSIONS
, PREFERENCES
),
533 EXPECT_TRUE(ModelTypeSetEquals(
534 ModelTypeSet(SESSIONS
, PREFERENCES
),
535 nudge_tracker_
.GetThrottledTypes()));
536 EXPECT_EQ(throttle2_length
,
537 nudge_tracker_
.GetTimeUntilNextUnthrottle(t0
));
539 // Setup the shorter interval.
540 nudge_tracker_
.SetTypesThrottledUntil(ModelTypeSet(SESSIONS
, BOOKMARKS
),
543 EXPECT_TRUE(ModelTypeSetEquals(
544 ModelTypeSet(SESSIONS
, PREFERENCES
, BOOKMARKS
),
545 nudge_tracker_
.GetThrottledTypes()));
546 EXPECT_EQ(throttle1_length
,
547 nudge_tracker_
.GetTimeUntilNextUnthrottle(t0
));
549 // Expire the first interval.
550 nudge_tracker_
.UpdateTypeThrottlingState(t1
);
552 // SESSIONS appeared in both intervals. We expect it will be throttled for
553 // the longer of the two, so it's still throttled at time t1.
554 EXPECT_TRUE(ModelTypeSetEquals(
555 ModelTypeSet(SESSIONS
, PREFERENCES
),
556 nudge_tracker_
.GetThrottledTypes()));
557 EXPECT_EQ(throttle2_length
- throttle1_length
,
558 nudge_tracker_
.GetTimeUntilNextUnthrottle(t1
));
560 // Expire the second interval.
561 nudge_tracker_
.UpdateTypeThrottlingState(t2
);
562 EXPECT_TRUE(nudge_tracker_
.GetThrottledTypes().Empty());
565 TEST_F(NudgeTrackerTest
, Retry
) {
566 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(12345);
567 const base::TimeTicks t3
= t0
+ base::TimeDelta::FromSeconds(3);
568 const base::TimeTicks t4
= t0
+ base::TimeDelta::FromSeconds(4);
571 nudge_tracker_
.SetNextRetryTime(t3
);
573 // Not due yet at t0.
574 nudge_tracker_
.SetSyncCycleStartTime(t0
);
575 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
576 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
578 // Successful sync cycle at t0 changes nothing.
579 nudge_tracker_
.RecordSuccessfulSyncCycle();
580 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
581 EXPECT_FALSE(nudge_tracker_
.IsGetUpdatesRequired());
583 // At t4, the retry becomes due.
584 nudge_tracker_
.SetSyncCycleStartTime(t4
);
585 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
586 EXPECT_TRUE(nudge_tracker_
.IsGetUpdatesRequired());
588 // A sync cycle unsets the flag.
589 nudge_tracker_
.RecordSuccessfulSyncCycle();
590 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
592 // It's still unset at the start of the next sync cycle.
593 nudge_tracker_
.SetSyncCycleStartTime(t4
);
594 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
597 // Test a mid-cycle update when IsRetryRequired() was true before the cycle
599 TEST_F(NudgeTrackerTest
, IsRetryRequired_MidCycleUpdate1
) {
600 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(12345);
601 const base::TimeTicks t1
= t0
+ base::TimeDelta::FromSeconds(1);
602 const base::TimeTicks t2
= t0
+ base::TimeDelta::FromSeconds(2);
603 const base::TimeTicks t5
= t0
+ base::TimeDelta::FromSeconds(5);
604 const base::TimeTicks t6
= t0
+ base::TimeDelta::FromSeconds(6);
606 nudge_tracker_
.SetNextRetryTime(t0
);
607 nudge_tracker_
.SetSyncCycleStartTime(t1
);
609 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
611 // Pretend that we were updated mid-cycle. SetSyncCycleStartTime is
612 // called only at the start of the sync cycle, so don't call it here.
613 // The update should have no effect on IsRetryRequired().
614 nudge_tracker_
.SetNextRetryTime(t5
);
616 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
618 // Verify that the successful sync cycle clears the flag.
619 nudge_tracker_
.RecordSuccessfulSyncCycle();
620 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
622 // Verify expecations around the new retry time.
623 nudge_tracker_
.SetSyncCycleStartTime(t2
);
624 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
626 nudge_tracker_
.SetSyncCycleStartTime(t6
);
627 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
630 // Test a mid-cycle update when IsRetryRequired() was false before the cycle
632 TEST_F(NudgeTrackerTest
, IsRetryRequired_MidCycleUpdate2
) {
633 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(12345);
634 const base::TimeTicks t1
= t0
+ base::TimeDelta::FromSeconds(1);
635 const base::TimeTicks t3
= t0
+ base::TimeDelta::FromSeconds(3);
636 const base::TimeTicks t5
= t0
+ base::TimeDelta::FromSeconds(5);
637 const base::TimeTicks t6
= t0
+ base::TimeDelta::FromSeconds(6);
639 // Schedule a future retry, and a nudge unrelated to it.
640 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
641 nudge_tracker_
.SetNextRetryTime(t1
);
642 nudge_tracker_
.SetSyncCycleStartTime(t0
);
643 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
645 // Pretend this happened in mid-cycle. This should have no effect on
646 // IsRetryRequired().
647 nudge_tracker_
.SetNextRetryTime(t5
);
648 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
650 // The cycle succeeded.
651 nudge_tracker_
.RecordSuccessfulSyncCycle();
653 // The time t3 is greater than the GU retry time scheduled at the beginning of
654 // the test, but later than the retry time that overwrote it during the
655 // pretend 'sync cycle'.
656 nudge_tracker_
.SetSyncCycleStartTime(t3
);
657 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
659 // Finally, the retry established during the sync cycle becomes due.
660 nudge_tracker_
.SetSyncCycleStartTime(t6
);
661 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
664 // Simulate the case where a sync cycle fails.
665 TEST_F(NudgeTrackerTest
, IsRetryRequired_FailedCycle
) {
666 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(12345);
667 const base::TimeTicks t1
= t0
+ base::TimeDelta::FromSeconds(1);
668 const base::TimeTicks t2
= t0
+ base::TimeDelta::FromSeconds(2);
670 nudge_tracker_
.SetNextRetryTime(t0
);
671 nudge_tracker_
.SetSyncCycleStartTime(t1
);
672 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
674 // The nudge tracker receives no notifications for a failed sync cycle.
675 // Pretend one happened here.
676 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
678 // Think of this as the retry cycle.
679 nudge_tracker_
.SetSyncCycleStartTime(t2
);
680 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
682 // The second cycle is a success.
683 nudge_tracker_
.RecordSuccessfulSyncCycle();
684 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
687 // Simulate a partially failed sync cycle. The callback to update the GU retry
688 // was invoked, but the sync cycle did not complete successfully.
689 TEST_F(NudgeTrackerTest
, IsRetryRequired_FailedCycleIncludesUpdate
) {
690 const base::TimeTicks t0
= base::TimeTicks::FromInternalValue(12345);
691 const base::TimeTicks t1
= t0
+ base::TimeDelta::FromSeconds(1);
692 const base::TimeTicks t3
= t0
+ base::TimeDelta::FromSeconds(3);
693 const base::TimeTicks t4
= t0
+ base::TimeDelta::FromSeconds(4);
694 const base::TimeTicks t5
= t0
+ base::TimeDelta::FromSeconds(5);
695 const base::TimeTicks t6
= t0
+ base::TimeDelta::FromSeconds(6);
697 nudge_tracker_
.SetNextRetryTime(t0
);
698 nudge_tracker_
.SetSyncCycleStartTime(t1
);
699 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
701 // The cycle is in progress. A new GU Retry time is received.
702 // The flag is not because this cycle is still in progress.
703 nudge_tracker_
.SetNextRetryTime(t5
);
704 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
706 // The nudge tracker receives no notifications for a failed sync cycle.
707 // Pretend the cycle failed here.
709 // The next sync cycle starts. The new GU time has not taken effect by this
710 // time, but the NudgeTracker hasn't forgotten that we have not yet serviced
711 // the retry from the previous cycle.
712 nudge_tracker_
.SetSyncCycleStartTime(t3
);
713 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
715 // It succeeds. The retry time is not updated, so it should remain at t5.
716 nudge_tracker_
.RecordSuccessfulSyncCycle();
718 // Another sync cycle. This one is still before the scheduled retry. It does
719 // not change the scheduled retry time.
720 nudge_tracker_
.SetSyncCycleStartTime(t4
);
721 EXPECT_FALSE(nudge_tracker_
.IsRetryRequired());
722 nudge_tracker_
.RecordSuccessfulSyncCycle();
724 // The retry scheduled way back during the first cycle of this test finally
725 // becomes due. Perform a successful sync cycle to service it.
726 nudge_tracker_
.SetSyncCycleStartTime(t6
);
727 EXPECT_TRUE(nudge_tracker_
.IsRetryRequired());
728 nudge_tracker_
.RecordSuccessfulSyncCycle();
731 // Test the default nudge delays for various types.
732 TEST_F(NudgeTrackerTest
, NudgeDelayTest
) {
733 // Set to a known value to compare against.
734 nudge_tracker_
.SetDefaultNudgeDelay(base::TimeDelta());
736 // Bookmarks and preference both have "slow nudge" delays.
737 EXPECT_EQ(nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
)),
738 nudge_tracker_
.RecordLocalChange(ModelTypeSet(PREFERENCES
)));
740 // Typed URLs has a default delay.
741 EXPECT_EQ(nudge_tracker_
.RecordLocalChange(ModelTypeSet(TYPED_URLS
)),
744 // "Slow nudge" delays are longer than the default.
745 EXPECT_GT(nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
)),
748 // Sessions is longer than "slow nudge".
749 EXPECT_GT(nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
)),
750 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
)));
752 // Favicons have the same delay as sessions.
753 EXPECT_EQ(nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
)),
754 nudge_tracker_
.RecordLocalChange(ModelTypeSet(FAVICON_TRACKING
)));
756 // Autofill has the longer delay of all.
757 EXPECT_GT(nudge_tracker_
.RecordLocalChange(ModelTypeSet(AUTOFILL
)),
758 nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
)));
760 // A nudge with no types takes the longest delay.
761 EXPECT_EQ(nudge_tracker_
.RecordLocalChange(ModelTypeSet(AUTOFILL
)),
762 nudge_tracker_
.RecordLocalChange(ModelTypeSet()));
764 // The actual nudge delay should be the shortest of the set.
766 nudge_tracker_
.RecordLocalChange(ModelTypeSet(TYPED_URLS
)),
767 nudge_tracker_
.RecordLocalChange(ModelTypeSet(TYPED_URLS
, AUTOFILL
)));
770 // Test that custom nudge delays are used over the defaults.
771 TEST_F(NudgeTrackerTest
, CustomDelayTest
) {
772 // Set some custom delays.
773 std::map
<ModelType
, base::TimeDelta
> delay_map
;
774 delay_map
[BOOKMARKS
] = base::TimeDelta::FromSeconds(10);
775 delay_map
[SESSIONS
] = base::TimeDelta::FromSeconds(2);
776 nudge_tracker_
.OnReceivedCustomNudgeDelays(delay_map
);
778 // Only those with custom delays should be affected, not another type.
779 EXPECT_NE(nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
)),
780 nudge_tracker_
.RecordLocalChange(ModelTypeSet(PREFERENCES
)));
782 EXPECT_EQ(base::TimeDelta::FromSeconds(10),
783 nudge_tracker_
.RecordLocalChange(ModelTypeSet(BOOKMARKS
)));
784 EXPECT_EQ(base::TimeDelta::FromSeconds(2),
785 nudge_tracker_
.RecordLocalChange(ModelTypeSet(SESSIONS
)));
788 // Check that custom nudge delays can never result in a value shorter than the
789 // minimum nudge delay.
790 TEST_F(NudgeTrackerTest
, NoTypesShorterThanDefault
) {
791 // Set delay to a known value.
792 nudge_tracker_
.SetDefaultNudgeDelay(base::TimeDelta::FromMilliseconds(500));
794 std::map
<ModelType
, base::TimeDelta
> delay_map
;
795 ModelTypeSet protocol_types
= syncer::ProtocolTypes();
796 for (ModelTypeSet::Iterator iter
= protocol_types
.First(); iter
.Good();
798 delay_map
[iter
.Get()] = base::TimeDelta();
800 nudge_tracker_
.OnReceivedCustomNudgeDelays(delay_map
);
802 // All types should still have a nudge greater than or equal to the minimum.
803 for (ModelTypeSet::Iterator iter
= protocol_types
.First(); iter
.Good();
805 EXPECT_GE(nudge_tracker_
.RecordLocalChange(ModelTypeSet(iter
.Get())),
806 base::TimeDelta::FromMilliseconds(500));
810 class NudgeTrackerAckTrackingTest
: public NudgeTrackerTest
{
812 NudgeTrackerAckTrackingTest() {}
814 bool IsInvalidationUnacknowledged(int tracking_id
) {
815 return tracker_
.IsUnacked(tracking_id
);
818 bool IsInvalidationAcknowledged(int tracking_id
) {
819 return tracker_
.IsAcknowledged(tracking_id
);
822 bool IsInvalidationDropped(int tracking_id
) {
823 return tracker_
.IsDropped(tracking_id
);
826 int SendInvalidation(ModelType type
, int version
, const std::string
& hint
) {
827 // Build and register the invalidation.
828 scoped_ptr
<TrackableMockInvalidation
> inv
=
829 tracker_
.IssueInvalidation(version
, hint
);
830 int id
= inv
->GetTrackingId();
832 // Send it to the NudgeTracker.
833 nudge_tracker_
.RecordRemoteInvalidation(
834 type
, inv
.PassAs
<InvalidationInterface
>());
836 // Return its ID to the test framework for use in assertions.
840 int SendUnknownVersionInvalidation(ModelType type
) {
841 // Build and register the invalidation.
842 scoped_ptr
<TrackableMockInvalidation
> inv
=
843 tracker_
.IssueUnknownVersionInvalidation();
844 int id
= inv
->GetTrackingId();
846 // Send it to the NudgeTracker.
847 nudge_tracker_
.RecordRemoteInvalidation(
848 type
, inv
.PassAs
<InvalidationInterface
>());
850 // Return its ID to the test framework for use in assertions.
854 bool AllInvalidationsAccountedFor() const {
855 return tracker_
.AllInvalidationsAccountedFor();
858 void RecordSuccessfulSyncCycle() {
859 nudge_tracker_
.RecordSuccessfulSyncCycle();
863 MockInvalidationTracker tracker_
;
866 // Test the acknowledgement of a single invalidation.
867 TEST_F(NudgeTrackerAckTrackingTest
, SimpleAcknowledgement
) {
868 int inv_id
= SendInvalidation(BOOKMARKS
, 10, "hint");
870 EXPECT_TRUE(IsInvalidationUnacknowledged(inv_id
));
872 RecordSuccessfulSyncCycle();
873 EXPECT_TRUE(IsInvalidationAcknowledged(inv_id
));
875 EXPECT_TRUE(AllInvalidationsAccountedFor());
878 // Test the acknowledgement of many invalidations.
879 TEST_F(NudgeTrackerAckTrackingTest
, ManyAcknowledgements
) {
880 int inv1_id
= SendInvalidation(BOOKMARKS
, 10, "hint");
881 int inv2_id
= SendInvalidation(BOOKMARKS
, 14, "hint2");
882 int inv3_id
= SendInvalidation(PREFERENCES
, 8, "hint3");
884 EXPECT_TRUE(IsInvalidationUnacknowledged(inv1_id
));
885 EXPECT_TRUE(IsInvalidationUnacknowledged(inv2_id
));
886 EXPECT_TRUE(IsInvalidationUnacknowledged(inv3_id
));
888 RecordSuccessfulSyncCycle();
889 EXPECT_TRUE(IsInvalidationAcknowledged(inv1_id
));
890 EXPECT_TRUE(IsInvalidationAcknowledged(inv2_id
));
891 EXPECT_TRUE(IsInvalidationAcknowledged(inv3_id
));
893 EXPECT_TRUE(AllInvalidationsAccountedFor());
896 // Test dropping when the buffer overflows and subsequent drop recovery.
897 TEST_F(NudgeTrackerAckTrackingTest
, OverflowAndRecover
) {
898 std::vector
<int> invalidation_ids
;
900 int inv10_id
= SendInvalidation(BOOKMARKS
, 10, "hint");
901 for (size_t i
= 1; i
< GetHintBufferSize(); ++i
) {
902 invalidation_ids
.push_back(SendInvalidation(BOOKMARKS
, i
+ 10, "hint"));
905 for (std::vector
<int>::iterator it
= invalidation_ids
.begin();
906 it
!= invalidation_ids
.end();
908 EXPECT_TRUE(IsInvalidationUnacknowledged(*it
));
911 // This invalidation, though arriving the most recently, has the oldest
912 // version number so it should be dropped first.
913 int inv5_id
= SendInvalidation(BOOKMARKS
, 5, "old_hint");
914 EXPECT_TRUE(IsInvalidationDropped(inv5_id
));
916 // This invalidation has a larger version number, so it will force a
917 // previously delivered invalidation to be dropped.
918 int inv100_id
= SendInvalidation(BOOKMARKS
, 100, "new_hint");
919 EXPECT_TRUE(IsInvalidationDropped(inv10_id
));
921 // This should recover from the drop and bring us back into sync.
922 RecordSuccessfulSyncCycle();
924 for (std::vector
<int>::iterator it
= invalidation_ids
.begin();
925 it
!= invalidation_ids
.end();
927 EXPECT_TRUE(IsInvalidationAcknowledged(*it
));
929 EXPECT_TRUE(IsInvalidationAcknowledged(inv100_id
));
931 EXPECT_TRUE(AllInvalidationsAccountedFor());
934 // Test receipt of an unknown version invalidation from the server.
935 TEST_F(NudgeTrackerAckTrackingTest
, UnknownVersionFromServer_Simple
) {
936 int inv_id
= SendUnknownVersionInvalidation(BOOKMARKS
);
937 EXPECT_TRUE(IsInvalidationUnacknowledged(inv_id
));
938 RecordSuccessfulSyncCycle();
939 EXPECT_TRUE(IsInvalidationAcknowledged(inv_id
));
940 EXPECT_TRUE(AllInvalidationsAccountedFor());
943 // Test receipt of multiple unknown version invalidations from the server.
944 TEST_F(NudgeTrackerAckTrackingTest
, UnknownVersionFromServer_Complex
) {
945 int inv1_id
= SendUnknownVersionInvalidation(BOOKMARKS
);
946 int inv2_id
= SendInvalidation(BOOKMARKS
, 10, "hint");
947 int inv3_id
= SendUnknownVersionInvalidation(BOOKMARKS
);
948 int inv4_id
= SendUnknownVersionInvalidation(BOOKMARKS
);
949 int inv5_id
= SendInvalidation(BOOKMARKS
, 20, "hint2");
951 // These invalidations have been overridden, so they got acked early.
952 EXPECT_TRUE(IsInvalidationAcknowledged(inv1_id
));
953 EXPECT_TRUE(IsInvalidationAcknowledged(inv3_id
));
955 // These invalidations are still waiting to be used.
956 EXPECT_TRUE(IsInvalidationUnacknowledged(inv2_id
));
957 EXPECT_TRUE(IsInvalidationUnacknowledged(inv4_id
));
958 EXPECT_TRUE(IsInvalidationUnacknowledged(inv5_id
));
960 // Finish the sync cycle and expect all remaining invalidations to be acked.
961 RecordSuccessfulSyncCycle();
962 EXPECT_TRUE(IsInvalidationAcknowledged(inv1_id
));
963 EXPECT_TRUE(IsInvalidationAcknowledged(inv2_id
));
964 EXPECT_TRUE(IsInvalidationAcknowledged(inv3_id
));
965 EXPECT_TRUE(IsInvalidationAcknowledged(inv4_id
));
966 EXPECT_TRUE(IsInvalidationAcknowledged(inv5_id
));
968 EXPECT_TRUE(AllInvalidationsAccountedFor());
971 } // namespace sessions
972 } // namespace syncer