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