1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "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"
13
14namespace syncer {
15
16namespace {
17
18testing::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);
25  }
26}
27
28}  // namespace
29
30namespace sessions {
31
32class NudgeTrackerTest : public ::testing::Test {
33 public:
34  NudgeTrackerTest() {
35    SetInvalidationsInSync();
36  }
37
38  static size_t GetHintBufferSize() {
39    // Assumes that no test has adjusted this size.
40    return NudgeTracker::kDefaultMaxPayloadsPerType;
41  }
42
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();
48  }
49
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();
54  }
55
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();
60  }
61
62  void SetInvalidationsInSync() {
63    nudge_tracker_.OnInvalidationsEnabled();
64    nudge_tracker_.RecordSuccessfulSyncCycle();
65  }
66
67  scoped_ptr<InvalidationInterface> BuildInvalidation(
68      int64 version,
69      const std::string& payload) {
70    return MockInvalidation::Build(version, payload)
71        .PassAs<InvalidationInterface>();
72  }
73
74  static scoped_ptr<InvalidationInterface> BuildUnknownVersionInvalidation() {
75    return MockInvalidation::BuildUnknownVersion()
76        .PassAs<InvalidationInterface>();
77  }
78
79 protected:
80  NudgeTracker nudge_tracker_;
81};
82
83// Exercise an empty NudgeTracker.
84// Use with valgrind to detect uninitialized members.
85TEST_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());
91
92  sync_pb::GetUpdateTriggers gu_trigger;
93  nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
94
95  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
96            nudge_tracker_.GetLegacySource());
97}
98
99// Verify that nudges override each other based on a priority order.
100// RETRY < LOCAL < DATATYPE_REFRESH < NOTIFICATION
101TEST_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());
109
110  // Track a local nudge.
111  nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
112  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
113            nudge_tracker_.GetLegacySource());
114
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());
119
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());
124
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());
130
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());
138}
139
140TEST_F(NudgeTrackerTest, SourcePriority_InitialSyncRequest) {
141  nudge_tracker_.RecordInitialSyncRequired(BOOKMARKS);
142
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());
147
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());
153
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());
159}
160
161// Verifies the management of invalidation hints and GU trigger fields.
162TEST_F(NudgeTrackerTest, HintCoalescing) {
163  // Easy case: record one hint.
164  {
165    nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
166                                            BuildInvalidation(1, "bm_hint_1"));
167
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());
173  }
174
175  // Record a second hint for the same type.
176  {
177    nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
178                                            BuildInvalidation(2, "bm_hint_2"));
179
180    sync_pb::GetUpdateTriggers gu_trigger;
181    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
182    ASSERT_EQ(2, gu_trigger.notification_hint_size());
183
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());
188  }
189
190  // Record a hint for a different type.
191  {
192    nudge_tracker_.RecordRemoteInvalidation(PASSWORDS,
193                                            BuildInvalidation(1, "pw_hint_1"));
194
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());
203
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());
210  }
211}
212
213// Test the dropping of invalidation hints.  Receives invalidations one by one.
214TEST_F(NudgeTrackerTest, DropHintsLocally_OneAtATime) {
215  for (size_t i = 0; i < GetHintBufferSize(); ++i) {
216    nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
217                                            BuildInvalidation(i, "hint"));
218  }
219  {
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());
225  }
226
227  // Force an overflow.
228  nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
229                                          BuildInvalidation(1000, "new_hint"));
230
231  {
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()));
237
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));
240
241    // Verify the oldest hint, too.
242    EXPECT_EQ("hint", gu_trigger.notification_hint(0));
243  }
244}
245
246// Tests the receipt of 'unknown version' invalidations.
247TEST_F(NudgeTrackerTest, DropHintsAtServer_Alone) {
248  // Record the unknown version invalidation.
249  nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
250                                          BuildUnknownVersionInvalidation());
251  {
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());
257  }
258
259  // Clear status then verify.
260  nudge_tracker_.RecordSuccessfulSyncCycle();
261  {
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());
267  }
268}
269
270// Tests the receipt of 'unknown version' invalidations.  This test also
271// includes a known version invalidation to mix things up a bit.
272TEST_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"));
278
279  {
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));
286  }
287
288  // Clear status then verify.
289  nudge_tracker_.RecordSuccessfulSyncCycle();
290  {
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());
296  }
297}
298
299// Checks the behaviour of the invalidations-out-of-sync flag.
300TEST_F(NudgeTrackerTest, EnableDisableInvalidations) {
301  // Start with invalidations offline.
302  nudge_tracker_.OnInvalidationsDisabled();
303  EXPECT_TRUE(InvalidationsOutOfSync());
304  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
305
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());
310
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());
316
317  // If the invalidator malfunctions, we go become unsynced again.
318  nudge_tracker_.OnInvalidationsDisabled();
319  EXPECT_TRUE(InvalidationsOutOfSync());
320  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
321
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());
326
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());
332}
333
334// Tests that locally modified types are correctly written out to the
335// GetUpdateTriggers proto.
336TEST_F(NudgeTrackerTest, WriteLocallyModifiedTypesToProto) {
337  // Should not be locally modified by default.
338  EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES));
339
340  // Record a local bookmark change.  Verify it was registered correctly.
341  nudge_tracker_.RecordLocalChange(ModelTypeSet(PREFERENCES));
342  EXPECT_EQ(1, ProtoLocallyModifiedCount(PREFERENCES));
343
344  // Record a successful sync cycle.  Verify the count is cleared.
345  nudge_tracker_.RecordSuccessfulSyncCycle();
346  EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES));
347}
348
349// Tests that refresh requested types are correctly written out to the
350// GetUpdateTriggers proto.
351TEST_F(NudgeTrackerTest, WriteRefreshRequestedTypesToProto) {
352  // There should be no refresh requested by default.
353  EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS));
354
355  // Record a local refresh request.  Verify it was registered correctly.
356  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
357  EXPECT_EQ(1, ProtoRefreshRequestedCount(SESSIONS));
358
359  // Record a successful sync cycle.  Verify the count is cleared.
360  nudge_tracker_.RecordSuccessfulSyncCycle();
361  EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS));
362}
363
364// Basic tests for the IsSyncRequired() flag.
365TEST_F(NudgeTrackerTest, IsSyncRequired) {
366  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
367
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());
373
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());
379
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());
385
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());
392}
393
394// Basic tests for the IsGetUpdatesRequired() flag.
395TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) {
396  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
397
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());
403
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());
409
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());
415
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());
422}
423
424// Test IsSyncRequired() responds correctly to data type throttling.
425TEST_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;
429
430  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
431
432  // A local change to sessions enables the flag.
433  nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
434  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
435
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());
441
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());
445
446  // A successful sync cycle means we took care of bookmarks.
447  nudge_tracker_.RecordSuccessfulSyncCycle();
448  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
449
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());
456}
457
458// Test IsGetUpdatesRequired() responds correctly to data type throttling.
459TEST_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;
463
464  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
465
466  // A refresh request to sessions enables the flag.
467  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
468  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
469
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());
475
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());
479
480  // A successful sync cycle means we took care of bookmarks.
481  nudge_tracker_.RecordSuccessfulSyncCycle();
482  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
483
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());
490}
491
492// Tests throttling-related getter functions when no types are throttled.
493TEST_F(NudgeTrackerTest, NoTypesThrottled) {
494  EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled());
495  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
496  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
497}
498
499// Tests throttling-related getter functions when some types are throttled.
500TEST_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;
504
505  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, PREFERENCES),
506                                       throttle_length,
507                                       t0);
508
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));
514
515  nudge_tracker_.UpdateTypeThrottlingState(t1);
516
517  EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled());
518  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
519  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
520}
521
522TEST_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;
528
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));
538
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));
548
549  // Expire the first interval.
550  nudge_tracker_.UpdateTypeThrottlingState(t1);
551
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));
559
560  // Expire the second interval.
561  nudge_tracker_.UpdateTypeThrottlingState(t2);
562  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
563}
564
565TEST_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);
569
570  // Set retry for t3.
571  nudge_tracker_.SetNextRetryTime(t3);
572
573  // Not due yet at t0.
574  nudge_tracker_.SetSyncCycleStartTime(t0);
575  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
576  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
577
578  // Successful sync cycle at t0 changes nothing.
579  nudge_tracker_.RecordSuccessfulSyncCycle();
580  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
581  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
582
583  // At t4, the retry becomes due.
584  nudge_tracker_.SetSyncCycleStartTime(t4);
585  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
586  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
587
588  // A sync cycle unsets the flag.
589  nudge_tracker_.RecordSuccessfulSyncCycle();
590  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
591
592  // It's still unset at the start of the next sync cycle.
593  nudge_tracker_.SetSyncCycleStartTime(t4);
594  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
595}
596
597// Test a mid-cycle update when IsRetryRequired() was true before the cycle
598// began.
599TEST_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);
605
606  nudge_tracker_.SetNextRetryTime(t0);
607  nudge_tracker_.SetSyncCycleStartTime(t1);
608
609  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
610
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);
615
616  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
617
618  // Verify that the successful sync cycle clears the flag.
619  nudge_tracker_.RecordSuccessfulSyncCycle();
620  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
621
622  // Verify expecations around the new retry time.
623  nudge_tracker_.SetSyncCycleStartTime(t2);
624  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
625
626  nudge_tracker_.SetSyncCycleStartTime(t6);
627  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
628}
629
630// Test a mid-cycle update when IsRetryRequired() was false before the cycle
631// began.
632TEST_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);
638
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());
644
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());
649
650  // The cycle succeeded.
651  nudge_tracker_.RecordSuccessfulSyncCycle();
652
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());
658
659  // Finally, the retry established during the sync cycle becomes due.
660  nudge_tracker_.SetSyncCycleStartTime(t6);
661  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
662}
663
664// Simulate the case where a sync cycle fails.
665TEST_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);
669
670  nudge_tracker_.SetNextRetryTime(t0);
671  nudge_tracker_.SetSyncCycleStartTime(t1);
672  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
673
674  // The nudge tracker receives no notifications for a failed sync cycle.
675  // Pretend one happened here.
676  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
677
678  // Think of this as the retry cycle.
679  nudge_tracker_.SetSyncCycleStartTime(t2);
680  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
681
682  // The second cycle is a success.
683  nudge_tracker_.RecordSuccessfulSyncCycle();
684  EXPECT_FALSE(nudge_tracker_.IsRetryRequired());
685}
686
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.
689TEST_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);
696
697  nudge_tracker_.SetNextRetryTime(t0);
698  nudge_tracker_.SetSyncCycleStartTime(t1);
699  EXPECT_TRUE(nudge_tracker_.IsRetryRequired());
700
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());
705
706  // The nudge tracker receives no notifications for a failed sync cycle.
707  // Pretend the cycle failed here.
708
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());
714
715  // It succeeds.  The retry time is not updated, so it should remain at t5.
716  nudge_tracker_.RecordSuccessfulSyncCycle();
717
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();
723
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();
729}
730
731// Test the default nudge delays for various types.
732TEST_F(NudgeTrackerTest, NudgeDelayTest) {
733  // Set to a known value to compare against.
734  nudge_tracker_.SetDefaultNudgeDelay(base::TimeDelta());
735
736  // Bookmarks and preference both have "slow nudge" delays.
737  EXPECT_EQ(nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS)),
738            nudge_tracker_.RecordLocalChange(ModelTypeSet(PREFERENCES)));
739
740  // Typed URLs has a default delay.
741  EXPECT_EQ(nudge_tracker_.RecordLocalChange(ModelTypeSet(TYPED_URLS)),
742            base::TimeDelta());
743
744  // "Slow nudge" delays are longer than the default.
745  EXPECT_GT(nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS)),
746            base::TimeDelta());
747
748  // Sessions is longer than "slow nudge".
749  EXPECT_GT(nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)),
750            nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS)));
751
752  // Favicons have the same delay as sessions.
753  EXPECT_EQ(nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)),
754            nudge_tracker_.RecordLocalChange(ModelTypeSet(FAVICON_TRACKING)));
755
756  // Autofill has the longer delay of all.
757  EXPECT_GT(nudge_tracker_.RecordLocalChange(ModelTypeSet(AUTOFILL)),
758            nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)));
759
760  // A nudge with no types takes the longest delay.
761  EXPECT_EQ(nudge_tracker_.RecordLocalChange(ModelTypeSet(AUTOFILL)),
762            nudge_tracker_.RecordLocalChange(ModelTypeSet()));
763
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)));
768}
769
770// Test that custom nudge delays are used over the defaults.
771TEST_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);
777
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)));
781
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)));
786}
787
788// Check that custom nudge delays can never result in a value shorter than the
789// minimum nudge delay.
790TEST_F(NudgeTrackerTest, NoTypesShorterThanDefault) {
791  // Set delay to a known value.
792  nudge_tracker_.SetDefaultNudgeDelay(base::TimeDelta::FromMilliseconds(500));
793
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();
799  }
800  nudge_tracker_.OnReceivedCustomNudgeDelays(delay_map);
801
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));
807  }
808}
809
810class NudgeTrackerAckTrackingTest : public NudgeTrackerTest {
811 public:
812  NudgeTrackerAckTrackingTest() {}
813
814  bool IsInvalidationUnacknowledged(int tracking_id) {
815    return tracker_.IsUnacked(tracking_id);
816  }
817
818  bool IsInvalidationAcknowledged(int tracking_id) {
819    return tracker_.IsAcknowledged(tracking_id);
820  }
821
822  bool IsInvalidationDropped(int tracking_id) {
823    return tracker_.IsDropped(tracking_id);
824  }
825
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();
831
832    // Send it to the NudgeTracker.
833    nudge_tracker_.RecordRemoteInvalidation(
834        type, inv.PassAs<InvalidationInterface>());
835
836    // Return its ID to the test framework for use in assertions.
837    return id;
838  }
839
840  int SendUnknownVersionInvalidation(ModelType type) {
841    // Build and register the invalidation.
842    scoped_ptr<TrackableMockInvalidation> inv =
843        tracker_.IssueUnknownVersionInvalidation();
844    int id = inv->GetTrackingId();
845
846    // Send it to the NudgeTracker.
847    nudge_tracker_.RecordRemoteInvalidation(
848        type, inv.PassAs<InvalidationInterface>());
849
850    // Return its ID to the test framework for use in assertions.
851    return id;
852  }
853
854  bool AllInvalidationsAccountedFor() const {
855    return tracker_.AllInvalidationsAccountedFor();
856  }
857
858  void RecordSuccessfulSyncCycle() {
859    nudge_tracker_.RecordSuccessfulSyncCycle();
860  }
861
862 private:
863  MockInvalidationTracker tracker_;
864};
865
866// Test the acknowledgement of a single invalidation.
867TEST_F(NudgeTrackerAckTrackingTest, SimpleAcknowledgement) {
868  int inv_id = SendInvalidation(BOOKMARKS, 10, "hint");
869
870  EXPECT_TRUE(IsInvalidationUnacknowledged(inv_id));
871
872  RecordSuccessfulSyncCycle();
873  EXPECT_TRUE(IsInvalidationAcknowledged(inv_id));
874
875  EXPECT_TRUE(AllInvalidationsAccountedFor());
876}
877
878// Test the acknowledgement of many invalidations.
879TEST_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");
883
884  EXPECT_TRUE(IsInvalidationUnacknowledged(inv1_id));
885  EXPECT_TRUE(IsInvalidationUnacknowledged(inv2_id));
886  EXPECT_TRUE(IsInvalidationUnacknowledged(inv3_id));
887
888  RecordSuccessfulSyncCycle();
889  EXPECT_TRUE(IsInvalidationAcknowledged(inv1_id));
890  EXPECT_TRUE(IsInvalidationAcknowledged(inv2_id));
891  EXPECT_TRUE(IsInvalidationAcknowledged(inv3_id));
892
893  EXPECT_TRUE(AllInvalidationsAccountedFor());
894}
895
896// Test dropping when the buffer overflows and subsequent drop recovery.
897TEST_F(NudgeTrackerAckTrackingTest, OverflowAndRecover) {
898  std::vector<int> invalidation_ids;
899
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"));
903  }
904
905  for (std::vector<int>::iterator it = invalidation_ids.begin();
906       it != invalidation_ids.end();
907       ++it) {
908    EXPECT_TRUE(IsInvalidationUnacknowledged(*it));
909  }
910
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));
915
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));
920
921  // This should recover from the drop and bring us back into sync.
922  RecordSuccessfulSyncCycle();
923
924  for (std::vector<int>::iterator it = invalidation_ids.begin();
925       it != invalidation_ids.end();
926       ++it) {
927    EXPECT_TRUE(IsInvalidationAcknowledged(*it));
928  }
929  EXPECT_TRUE(IsInvalidationAcknowledged(inv100_id));
930
931  EXPECT_TRUE(AllInvalidationsAccountedFor());
932}
933
934// Test receipt of an unknown version invalidation from the server.
935TEST_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());
941}
942
943// Test receipt of multiple unknown version invalidations from the server.
944TEST_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");
950
951  // These invalidations have been overridden, so they got acked early.
952  EXPECT_TRUE(IsInvalidationAcknowledged(inv1_id));
953  EXPECT_TRUE(IsInvalidationAcknowledged(inv3_id));
954
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));
959
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));
967
968  EXPECT_TRUE(AllInvalidationsAccountedFor());
969}
970
971}  // namespace sessions
972}  // namespace syncer
973