Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / sync / sessions / nudge_tracker_unittest.cc
blob50b596b7f6120e44d642b1b3373c9a0d527eb0ac
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"
14 namespace syncer {
16 namespace {
18 testing::AssertionResult ModelTypeSetEquals(ModelTypeSet a, ModelTypeSet b) {
19 if (a.Equals(b)) {
20 return testing::AssertionSuccess();
21 } else {
22 return testing::AssertionFailure()
23 << "Left side " << ModelTypeSetToString(a)
24 << ", does not match rigth side: " << ModelTypeSetToString(b);
28 } // namespace
30 namespace sessions {
32 class NudgeTrackerTest : public ::testing::Test {
33 public:
34 NudgeTrackerTest() {
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(
68 int64 version,
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>();
79 protected:
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());
374 // Local changes.
375 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
376 EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
377 nudge_tracker_.RecordSuccessfulSyncCycle();
378 EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
380 // Refresh requests.
381 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
382 EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
383 nudge_tracker_.RecordSuccessfulSyncCycle();
384 EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
386 // Invalidations.
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());
404 // Local changes.
405 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
406 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
407 nudge_tracker_.RecordSuccessfulSyncCycle();
408 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
410 // Refresh requests.
411 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
412 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
413 nudge_tracker_.RecordSuccessfulSyncCycle();
414 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
416 // Invalidations.
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),
438 throttle_length,
439 t0);
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),
472 throttle_length,
473 t0);
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),
506 throttle_length,
507 t0);
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),
531 throttle2_length,
532 t0);
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),
541 throttle1_length,
542 t0);
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);
570 // Set retry for t3.
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
598 // began.
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
631 // began.
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)),
742 base::TimeDelta());
744 // "Slow nudge" delays are longer than the default.
745 EXPECT_GT(nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS)),
746 base::TimeDelta());
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.
765 EXPECT_EQ(
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();
797 iter.Inc()) {
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();
804 iter.Inc()) {
805 EXPECT_GE(nudge_tracker_.RecordLocalChange(ModelTypeSet(iter.Get())),
806 base::TimeDelta::FromMilliseconds(500));
810 class NudgeTrackerAckTrackingTest : public NudgeTrackerTest {
811 public:
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.
837 return id;
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.
851 return id;
854 bool AllInvalidationsAccountedFor() const {
855 return tracker_.AllInvalidationsAccountedFor();
858 void RecordSuccessfulSyncCycle() {
859 nudge_tracker_.RecordSuccessfulSyncCycle();
862 private:
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();
907 ++it) {
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();
926 ++it) {
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