1 // Copyright 2014 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 <cstddef> 6 #include <map> 7 #include <set> 8 #include <string> 9 #include <vector> 10 11 #include "base/compiler_specific.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/stl_util.h" 14 #include "components/invalidation/fake_invalidation_state_tracker.h" 15 #include "components/invalidation/invalidation_util.h" 16 #include "components/invalidation/object_id_invalidation_map.h" 17 #include "components/invalidation/push_client_channel.h" 18 #include "components/invalidation/sync_invalidation_listener.h" 19 #include "components/invalidation/unacked_invalidation_set_test_util.h" 20 #include "google/cacheinvalidation/include/invalidation-client.h" 21 #include "google/cacheinvalidation/include/types.h" 22 #include "jingle/notifier/listener/fake_push_client.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 namespace syncer { 26 27 namespace { 28 29 using invalidation::AckHandle; 30 using invalidation::ObjectId; 31 32 const char kClientId[] = "client_id"; 33 const char kClientInfo[] = "client_info"; 34 35 const char kState[] = "state"; 36 const char kNewState[] = "new_state"; 37 38 const char kPayload1[] = "payload1"; 39 const char kPayload2[] = "payload2"; 40 41 const int64 kVersion1 = 1LL; 42 const int64 kVersion2 = 2LL; 43 44 const int kChromeSyncSourceId = 1004; 45 46 struct AckHandleLessThan { 47 bool operator()(const AckHandle& lhs, const AckHandle& rhs) const { 48 return lhs.handle_data() < rhs.handle_data(); 49 } 50 }; 51 52 typedef std::set<AckHandle, AckHandleLessThan> AckHandleSet; 53 54 // Fake invalidation::InvalidationClient implementation that keeps 55 // track of registered IDs and acked handles. 56 class FakeInvalidationClient : public invalidation::InvalidationClient { 57 public: 58 FakeInvalidationClient() : started_(false) {} 59 virtual ~FakeInvalidationClient() {} 60 61 const ObjectIdSet& GetRegisteredIds() const { 62 return registered_ids_; 63 } 64 65 void ClearAckedHandles() { 66 acked_handles_.clear(); 67 } 68 69 bool IsAckedHandle(const AckHandle& ack_handle) const { 70 return (acked_handles_.find(ack_handle) != acked_handles_.end()); 71 } 72 73 // invalidation::InvalidationClient implementation. 74 75 virtual void Start() OVERRIDE { 76 started_ = true; 77 } 78 79 virtual void Stop() OVERRIDE { 80 started_ = false; 81 } 82 83 virtual void Register(const ObjectId& object_id) OVERRIDE { 84 if (!started_) { 85 ADD_FAILURE(); 86 return; 87 } 88 registered_ids_.insert(object_id); 89 } 90 91 virtual void Register( 92 const invalidation::vector<ObjectId>& object_ids) OVERRIDE { 93 if (!started_) { 94 ADD_FAILURE(); 95 return; 96 } 97 registered_ids_.insert(object_ids.begin(), object_ids.end()); 98 } 99 100 virtual void Unregister(const ObjectId& object_id) OVERRIDE { 101 if (!started_) { 102 ADD_FAILURE(); 103 return; 104 } 105 registered_ids_.erase(object_id); 106 } 107 108 virtual void Unregister( 109 const invalidation::vector<ObjectId>& object_ids) OVERRIDE { 110 if (!started_) { 111 ADD_FAILURE(); 112 return; 113 } 114 for (invalidation::vector<ObjectId>::const_iterator 115 it = object_ids.begin(); it != object_ids.end(); ++it) { 116 registered_ids_.erase(*it); 117 } 118 } 119 120 virtual void Acknowledge(const AckHandle& ack_handle) OVERRIDE { 121 if (!started_) { 122 ADD_FAILURE(); 123 return; 124 } 125 acked_handles_.insert(ack_handle); 126 } 127 128 private: 129 bool started_; 130 ObjectIdSet registered_ids_; 131 AckHandleSet acked_handles_; 132 }; 133 134 // Fake delegate tkat keeps track of invalidation counts, payloads, 135 // and state. 136 class FakeDelegate : public SyncInvalidationListener::Delegate { 137 public: 138 explicit FakeDelegate(SyncInvalidationListener* listener) 139 : state_(TRANSIENT_INVALIDATION_ERROR) {} 140 virtual ~FakeDelegate() {} 141 142 size_t GetInvalidationCount(const ObjectId& id) const { 143 Map::const_iterator it = invalidations_.find(id); 144 if (it == invalidations_.end()) { 145 return 0; 146 } else { 147 return it->second.size(); 148 } 149 } 150 151 int64 GetVersion(const ObjectId& id) const { 152 Map::const_iterator it = invalidations_.find(id); 153 if (it == invalidations_.end()) { 154 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id); 155 return 0; 156 } else { 157 return it->second.back().version(); 158 } 159 } 160 161 std::string GetPayload(const ObjectId& id) const { 162 Map::const_iterator it = invalidations_.find(id); 163 if (it == invalidations_.end()) { 164 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id); 165 return 0; 166 } else { 167 return it->second.back().payload(); 168 } 169 } 170 171 bool IsUnknownVersion(const ObjectId& id) const { 172 Map::const_iterator it = invalidations_.find(id); 173 if (it == invalidations_.end()) { 174 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id); 175 return false; 176 } else { 177 return it->second.back().is_unknown_version(); 178 } 179 } 180 181 bool StartsWithUnknownVersion(const ObjectId& id) const { 182 Map::const_iterator it = invalidations_.find(id); 183 if (it == invalidations_.end()) { 184 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id); 185 return false; 186 } else { 187 return it->second.front().is_unknown_version(); 188 } 189 } 190 191 InvalidatorState GetInvalidatorState() const { 192 return state_; 193 } 194 195 void AcknowledgeNthInvalidation(const ObjectId& id, size_t n) { 196 List& list = invalidations_[id]; 197 List::iterator it = list.begin() + n; 198 it->Acknowledge(); 199 } 200 201 void AcknowledgeAll(const ObjectId& id) { 202 List& list = invalidations_[id]; 203 for (List::iterator it = list.begin(); it != list.end(); ++it) { 204 it->Acknowledge(); 205 } 206 } 207 208 void DropNthInvalidation(const ObjectId& id, size_t n) { 209 List& list = invalidations_[id]; 210 List::iterator it = list.begin() + n; 211 it->Drop(); 212 dropped_invalidations_map_.erase(id); 213 dropped_invalidations_map_.insert(std::make_pair(id, *it)); 214 } 215 216 void RecoverFromDropEvent(const ObjectId& id) { 217 DropMap::iterator it = dropped_invalidations_map_.find(id); 218 if (it != dropped_invalidations_map_.end()) { 219 it->second.Acknowledge(); 220 dropped_invalidations_map_.erase(it); 221 } 222 } 223 224 // SyncInvalidationListener::Delegate implementation. 225 virtual void OnInvalidate( 226 const ObjectIdInvalidationMap& invalidation_map) OVERRIDE { 227 ObjectIdSet ids = invalidation_map.GetObjectIds(); 228 for (ObjectIdSet::iterator it = ids.begin(); it != ids.end(); ++it) { 229 const SingleObjectInvalidationSet& incoming = 230 invalidation_map.ForObject(*it); 231 List& list = invalidations_[*it]; 232 list.insert(list.end(), incoming.begin(), incoming.end()); 233 } 234 } 235 236 virtual void OnInvalidatorStateChange(InvalidatorState state) OVERRIDE { 237 state_ = state; 238 } 239 240 private: 241 typedef std::vector<Invalidation> List; 242 typedef std::map<ObjectId, List, ObjectIdLessThan> Map; 243 typedef std::map<ObjectId, Invalidation, ObjectIdLessThan> DropMap; 244 245 Map invalidations_; 246 InvalidatorState state_; 247 DropMap dropped_invalidations_map_; 248 }; 249 250 invalidation::InvalidationClient* CreateFakeInvalidationClient( 251 FakeInvalidationClient** fake_invalidation_client, 252 invalidation::SystemResources* resources, 253 int client_type, 254 const invalidation::string& client_name, 255 const invalidation::string& application_name, 256 invalidation::InvalidationListener* listener) { 257 *fake_invalidation_client = new FakeInvalidationClient(); 258 return *fake_invalidation_client; 259 } 260 261 class SyncInvalidationListenerTest : public testing::Test { 262 protected: 263 SyncInvalidationListenerTest() 264 : kBookmarksId_(kChromeSyncSourceId, "BOOKMARK"), 265 kPreferencesId_(kChromeSyncSourceId, "PREFERENCE"), 266 kExtensionsId_(kChromeSyncSourceId, "EXTENSION"), 267 kAppsId_(kChromeSyncSourceId, "APP"), 268 fake_push_client_(new notifier::FakePushClient()), 269 fake_invalidation_client_(NULL), 270 listener_(scoped_ptr<SyncNetworkChannel>(new PushClientChannel( 271 scoped_ptr<notifier::PushClient>(fake_push_client_)))), 272 fake_delegate_(&listener_) {} 273 274 virtual void SetUp() { 275 StartClient(); 276 277 registered_ids_.insert(kBookmarksId_); 278 registered_ids_.insert(kPreferencesId_); 279 listener_.UpdateRegisteredIds(registered_ids_); 280 } 281 282 virtual void TearDown() { 283 StopClient(); 284 } 285 286 // Restart client without re-registering IDs. 287 void RestartClient() { 288 StopClient(); 289 StartClient(); 290 } 291 292 void StartClient() { 293 fake_invalidation_client_ = NULL; 294 listener_.Start( 295 base::Bind(&CreateFakeInvalidationClient, &fake_invalidation_client_), 296 kClientId, 297 kClientInfo, 298 kState, 299 fake_tracker_.GetSavedInvalidations(), 300 fake_tracker_.AsWeakPtr(), 301 base::MessageLoopProxy::current(), 302 &fake_delegate_); 303 DCHECK(fake_invalidation_client_); 304 } 305 306 void StopClient() { 307 // listener_.StopForTest() stops the invalidation scheduler, which 308 // deletes any pending tasks without running them. Some tasks 309 // "run and delete" another task, so they must be run in order to 310 // avoid leaking the inner task. listener_.StopForTest() does not 311 // schedule any tasks, so it's both necessary and sufficient to 312 // drain the task queue before calling it. 313 FlushPendingWrites(); 314 fake_invalidation_client_ = NULL; 315 listener_.StopForTest(); 316 } 317 318 size_t GetInvalidationCount(const ObjectId& id) const { 319 return fake_delegate_.GetInvalidationCount(id); 320 } 321 322 int64 GetVersion(const ObjectId& id) const { 323 return fake_delegate_.GetVersion(id); 324 } 325 326 std::string GetPayload(const ObjectId& id) const { 327 return fake_delegate_.GetPayload(id); 328 } 329 330 bool IsUnknownVersion(const ObjectId& id) const { 331 return fake_delegate_.IsUnknownVersion(id); 332 } 333 334 bool StartsWithUnknownVersion(const ObjectId& id) const { 335 return fake_delegate_.StartsWithUnknownVersion(id); 336 } 337 338 void AcknowledgeNthInvalidation(const ObjectId& id, size_t n) { 339 fake_delegate_.AcknowledgeNthInvalidation(id, n); 340 } 341 342 void DropNthInvalidation(const ObjectId& id, size_t n) { 343 return fake_delegate_.DropNthInvalidation(id, n); 344 } 345 346 void RecoverFromDropEvent(const ObjectId& id) { 347 return fake_delegate_.RecoverFromDropEvent(id); 348 } 349 350 void AcknowledgeAll(const ObjectId& id) { 351 fake_delegate_.AcknowledgeAll(id); 352 } 353 354 InvalidatorState GetInvalidatorState() const { 355 return fake_delegate_.GetInvalidatorState(); 356 } 357 358 std::string GetInvalidatorClientId() const { 359 return fake_tracker_.GetInvalidatorClientId(); 360 } 361 362 std::string GetBootstrapData() const { 363 return fake_tracker_.GetBootstrapData(); 364 } 365 366 UnackedInvalidationsMap GetSavedInvalidations() { 367 // Allow any queued writes to go through first. 368 FlushPendingWrites(); 369 return fake_tracker_.GetSavedInvalidations(); 370 } 371 372 SingleObjectInvalidationSet GetSavedInvalidationsForType(const ObjectId& id) { 373 const UnackedInvalidationsMap& saved_state = GetSavedInvalidations(); 374 UnackedInvalidationsMap::const_iterator it = 375 saved_state.find(kBookmarksId_); 376 if (it == saved_state.end()) { 377 ADD_FAILURE() << "No state saved for ID " << ObjectIdToString(id); 378 return SingleObjectInvalidationSet(); 379 } 380 ObjectIdInvalidationMap map; 381 it->second.ExportInvalidations( 382 base::WeakPtr<AckHandler>(), 383 scoped_refptr<base::SingleThreadTaskRunner>(), 384 &map); 385 if (map.Empty()) { 386 return SingleObjectInvalidationSet(); 387 } else { 388 return map.ForObject(id); 389 } 390 } 391 392 ObjectIdSet GetRegisteredIds() const { 393 return fake_invalidation_client_->GetRegisteredIds(); 394 } 395 396 // |payload| can be NULL. 397 void FireInvalidate(const ObjectId& object_id, 398 int64 version, const char* payload) { 399 invalidation::Invalidation inv; 400 if (payload) { 401 inv = invalidation::Invalidation(object_id, version, payload); 402 } else { 403 inv = invalidation::Invalidation(object_id, version); 404 } 405 const AckHandle ack_handle("fakedata"); 406 fake_invalidation_client_->ClearAckedHandles(); 407 listener_.Invalidate(fake_invalidation_client_, inv, ack_handle); 408 EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); 409 } 410 411 // |payload| can be NULL, but not |type_name|. 412 void FireInvalidateUnknownVersion(const ObjectId& object_id) { 413 const AckHandle ack_handle("fakedata_unknown"); 414 fake_invalidation_client_->ClearAckedHandles(); 415 listener_.InvalidateUnknownVersion(fake_invalidation_client_, 416 object_id, 417 ack_handle); 418 EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); 419 } 420 421 void FireInvalidateAll() { 422 const AckHandle ack_handle("fakedata_all"); 423 fake_invalidation_client_->ClearAckedHandles(); 424 listener_.InvalidateAll(fake_invalidation_client_, ack_handle); 425 EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); 426 } 427 428 void WriteState(const std::string& new_state) { 429 listener_.WriteState(new_state); 430 431 // Pump message loop to trigger 432 // InvalidationStateTracker::WriteState(). 433 FlushPendingWrites(); 434 } 435 436 void FlushPendingWrites() { 437 message_loop_.RunUntilIdle(); 438 } 439 440 void EnableNotifications() { 441 fake_push_client_->EnableNotifications(); 442 } 443 444 void DisableNotifications(notifier::NotificationsDisabledReason reason) { 445 fake_push_client_->DisableNotifications(reason); 446 } 447 448 const ObjectId kBookmarksId_; 449 const ObjectId kPreferencesId_; 450 const ObjectId kExtensionsId_; 451 const ObjectId kAppsId_; 452 453 ObjectIdSet registered_ids_; 454 455 private: 456 base::MessageLoop message_loop_; 457 notifier::FakePushClient* const fake_push_client_; 458 459 protected: 460 // A derrived test needs direct access to this. 461 FakeInvalidationStateTracker fake_tracker_; 462 463 // Tests need to access these directly. 464 FakeInvalidationClient* fake_invalidation_client_; 465 SyncInvalidationListener listener_; 466 467 private: 468 FakeDelegate fake_delegate_; 469 }; 470 471 // Write a new state to the client. It should propagate to the 472 // tracker. 473 TEST_F(SyncInvalidationListenerTest, WriteState) { 474 WriteState(kNewState); 475 476 EXPECT_EQ(kNewState, GetBootstrapData()); 477 } 478 479 // Invalidation tests. 480 481 // Fire an invalidation without a payload. It should be processed, 482 // the payload should remain empty, and the version should be updated. 483 TEST_F(SyncInvalidationListenerTest, InvalidateNoPayload) { 484 const ObjectId& id = kBookmarksId_; 485 486 FireInvalidate(id, kVersion1, NULL); 487 488 ASSERT_EQ(1U, GetInvalidationCount(id)); 489 ASSERT_FALSE(IsUnknownVersion(id)); 490 EXPECT_EQ(kVersion1, GetVersion(id)); 491 EXPECT_EQ("", GetPayload(id)); 492 } 493 494 // Fire an invalidation with an empty payload. It should be 495 // processed, the payload should remain empty, and the version should 496 // be updated. 497 TEST_F(SyncInvalidationListenerTest, InvalidateEmptyPayload) { 498 const ObjectId& id = kBookmarksId_; 499 500 FireInvalidate(id, kVersion1, ""); 501 502 ASSERT_EQ(1U, GetInvalidationCount(id)); 503 ASSERT_FALSE(IsUnknownVersion(id)); 504 EXPECT_EQ(kVersion1, GetVersion(id)); 505 EXPECT_EQ("", GetPayload(id)); 506 } 507 508 // Fire an invalidation with a payload. It should be processed, and 509 // both the payload and the version should be updated. 510 TEST_F(SyncInvalidationListenerTest, InvalidateWithPayload) { 511 const ObjectId& id = kPreferencesId_; 512 513 FireInvalidate(id, kVersion1, kPayload1); 514 515 ASSERT_EQ(1U, GetInvalidationCount(id)); 516 ASSERT_FALSE(IsUnknownVersion(id)); 517 EXPECT_EQ(kVersion1, GetVersion(id)); 518 EXPECT_EQ(kPayload1, GetPayload(id)); 519 } 520 521 // Fire ten invalidations in a row. All should be received. 522 TEST_F(SyncInvalidationListenerTest, ManyInvalidations_NoDrop) { 523 const int kRepeatCount = 10; 524 const ObjectId& id = kPreferencesId_; 525 int64 initial_version = kVersion1; 526 for (int64 i = initial_version; i < initial_version + kRepeatCount; ++i) { 527 FireInvalidate(id, i, kPayload1); 528 } 529 ASSERT_EQ(static_cast<size_t>(kRepeatCount), GetInvalidationCount(id)); 530 ASSERT_FALSE(IsUnknownVersion(id)); 531 EXPECT_EQ(kPayload1, GetPayload(id)); 532 EXPECT_EQ(initial_version + kRepeatCount - 1, GetVersion(id)); 533 } 534 535 // Fire an invalidation for an unregistered object ID with a payload. It should 536 // still be processed, and both the payload and the version should be updated. 537 TEST_F(SyncInvalidationListenerTest, InvalidateBeforeRegistration_Simple) { 538 const ObjectId kUnregisteredId(kChromeSyncSourceId, "unregistered"); 539 const ObjectId& id = kUnregisteredId; 540 ObjectIdSet ids; 541 ids.insert(id); 542 543 EXPECT_EQ(0U, GetInvalidationCount(id)); 544 545 FireInvalidate(id, kVersion1, kPayload1); 546 547 ASSERT_EQ(0U, GetInvalidationCount(id)); 548 549 EnableNotifications(); 550 listener_.Ready(fake_invalidation_client_); 551 listener_.UpdateRegisteredIds(ids); 552 553 ASSERT_EQ(1U, GetInvalidationCount(id)); 554 ASSERT_FALSE(IsUnknownVersion(id)); 555 EXPECT_EQ(kVersion1, GetVersion(id)); 556 EXPECT_EQ(kPayload1, GetPayload(id)); 557 } 558 559 // Fire ten invalidations before an object registers. Some invalidations will 560 // be dropped an replaced with an unknown version invalidation. 561 TEST_F(SyncInvalidationListenerTest, InvalidateBeforeRegistration_Drop) { 562 const int kRepeatCount = 563 UnackedInvalidationSet::kMaxBufferedInvalidations + 1; 564 const ObjectId kUnregisteredId(kChromeSyncSourceId, "unregistered"); 565 const ObjectId& id = kUnregisteredId; 566 ObjectIdSet ids; 567 ids.insert(id); 568 569 EXPECT_EQ(0U, GetInvalidationCount(id)); 570 571 int64 initial_version = kVersion1; 572 for (int64 i = initial_version; i < initial_version + kRepeatCount; ++i) { 573 FireInvalidate(id, i, kPayload1); 574 } 575 576 EnableNotifications(); 577 listener_.Ready(fake_invalidation_client_); 578 listener_.UpdateRegisteredIds(ids); 579 580 ASSERT_EQ(UnackedInvalidationSet::kMaxBufferedInvalidations, 581 GetInvalidationCount(id)); 582 ASSERT_FALSE(IsUnknownVersion(id)); 583 EXPECT_EQ(initial_version + kRepeatCount - 1, GetVersion(id)); 584 EXPECT_EQ(kPayload1, GetPayload(id)); 585 EXPECT_TRUE(StartsWithUnknownVersion(id)); 586 } 587 588 // Fire an invalidation, then fire another one with a lower version. Both 589 // should be received. 590 TEST_F(SyncInvalidationListenerTest, InvalidateVersion) { 591 const ObjectId& id = kPreferencesId_; 592 593 FireInvalidate(id, kVersion2, kPayload2); 594 595 ASSERT_EQ(1U, GetInvalidationCount(id)); 596 ASSERT_FALSE(IsUnknownVersion(id)); 597 EXPECT_EQ(kVersion2, GetVersion(id)); 598 EXPECT_EQ(kPayload2, GetPayload(id)); 599 600 FireInvalidate(id, kVersion1, kPayload1); 601 602 ASSERT_EQ(2U, GetInvalidationCount(id)); 603 ASSERT_FALSE(IsUnknownVersion(id)); 604 605 EXPECT_EQ(kVersion1, GetVersion(id)); 606 EXPECT_EQ(kPayload1, GetPayload(id)); 607 } 608 609 // Fire an invalidation with an unknown version. 610 TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) { 611 const ObjectId& id = kBookmarksId_; 612 613 FireInvalidateUnknownVersion(id); 614 615 ASSERT_EQ(1U, GetInvalidationCount(id)); 616 EXPECT_TRUE(IsUnknownVersion(id)); 617 } 618 619 // Fire an invalidation for all enabled IDs. 620 TEST_F(SyncInvalidationListenerTest, InvalidateAll) { 621 FireInvalidateAll(); 622 623 for (ObjectIdSet::const_iterator it = registered_ids_.begin(); 624 it != registered_ids_.end(); ++it) { 625 ASSERT_EQ(1U, GetInvalidationCount(*it)); 626 EXPECT_TRUE(IsUnknownVersion(*it)); 627 } 628 } 629 630 // Test a simple scenario for multiple IDs. 631 TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { 632 FireInvalidate(kBookmarksId_, 3, NULL); 633 634 ASSERT_EQ(1U, GetInvalidationCount(kBookmarksId_)); 635 ASSERT_FALSE(IsUnknownVersion(kBookmarksId_)); 636 EXPECT_EQ(3, GetVersion(kBookmarksId_)); 637 EXPECT_EQ("", GetPayload(kBookmarksId_)); 638 639 // kExtensionId is not registered, so the invalidation should not get through. 640 FireInvalidate(kExtensionsId_, 2, NULL); 641 ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_)); 642 } 643 644 // Registration tests. 645 646 // With IDs already registered, enable notifications then ready the 647 // client. The IDs should be registered only after the client is 648 // readied. 649 TEST_F(SyncInvalidationListenerTest, RegisterEnableReady) { 650 EXPECT_TRUE(GetRegisteredIds().empty()); 651 652 EnableNotifications(); 653 654 EXPECT_TRUE(GetRegisteredIds().empty()); 655 656 listener_.Ready(fake_invalidation_client_); 657 658 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 659 } 660 661 // With IDs already registered, ready the client then enable 662 // notifications. The IDs should be registered after the client is 663 // readied. 664 TEST_F(SyncInvalidationListenerTest, RegisterReadyEnable) { 665 EXPECT_TRUE(GetRegisteredIds().empty()); 666 667 listener_.Ready(fake_invalidation_client_); 668 669 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 670 671 EnableNotifications(); 672 673 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 674 } 675 676 // Unregister the IDs, enable notifications, re-register the IDs, then 677 // ready the client. The IDs should be registered only after the 678 // client is readied. 679 TEST_F(SyncInvalidationListenerTest, EnableRegisterReady) { 680 listener_.UpdateRegisteredIds(ObjectIdSet()); 681 682 EXPECT_TRUE(GetRegisteredIds().empty()); 683 684 EnableNotifications(); 685 686 EXPECT_TRUE(GetRegisteredIds().empty()); 687 688 listener_.UpdateRegisteredIds(registered_ids_); 689 690 EXPECT_TRUE(GetRegisteredIds().empty()); 691 692 listener_.Ready(fake_invalidation_client_); 693 694 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 695 } 696 697 // Unregister the IDs, enable notifications, ready the client, then 698 // re-register the IDs. The IDs should be registered only after the 699 // client is readied. 700 TEST_F(SyncInvalidationListenerTest, EnableReadyRegister) { 701 listener_.UpdateRegisteredIds(ObjectIdSet()); 702 703 EXPECT_TRUE(GetRegisteredIds().empty()); 704 705 EnableNotifications(); 706 707 EXPECT_TRUE(GetRegisteredIds().empty()); 708 709 listener_.Ready(fake_invalidation_client_); 710 711 EXPECT_TRUE(GetRegisteredIds().empty()); 712 713 listener_.UpdateRegisteredIds(registered_ids_); 714 715 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 716 } 717 718 // Unregister the IDs, ready the client, enable notifications, then 719 // re-register the IDs. The IDs should be registered only after the 720 // client is readied. 721 TEST_F(SyncInvalidationListenerTest, ReadyEnableRegister) { 722 listener_.UpdateRegisteredIds(ObjectIdSet()); 723 724 EXPECT_TRUE(GetRegisteredIds().empty()); 725 726 EnableNotifications(); 727 728 EXPECT_TRUE(GetRegisteredIds().empty()); 729 730 listener_.Ready(fake_invalidation_client_); 731 732 EXPECT_TRUE(GetRegisteredIds().empty()); 733 734 listener_.UpdateRegisteredIds(registered_ids_); 735 736 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 737 } 738 739 // Unregister the IDs, ready the client, re-register the IDs, then 740 // enable notifications. The IDs should be registered only after the 741 // client is readied. 742 // 743 // This test is important: see http://crbug.com/139424. 744 TEST_F(SyncInvalidationListenerTest, ReadyRegisterEnable) { 745 listener_.UpdateRegisteredIds(ObjectIdSet()); 746 747 EXPECT_TRUE(GetRegisteredIds().empty()); 748 749 listener_.Ready(fake_invalidation_client_); 750 751 EXPECT_TRUE(GetRegisteredIds().empty()); 752 753 listener_.UpdateRegisteredIds(registered_ids_); 754 755 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 756 757 EnableNotifications(); 758 759 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 760 } 761 762 // With IDs already registered, ready the client, restart the client, 763 // then re-ready it. The IDs should still be registered. 764 TEST_F(SyncInvalidationListenerTest, RegisterTypesPreserved) { 765 EXPECT_TRUE(GetRegisteredIds().empty()); 766 767 listener_.Ready(fake_invalidation_client_); 768 769 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 770 771 RestartClient(); 772 773 EXPECT_TRUE(GetRegisteredIds().empty()); 774 775 listener_.Ready(fake_invalidation_client_); 776 777 EXPECT_EQ(registered_ids_, GetRegisteredIds()); 778 } 779 780 // Make sure that state is correctly purged from the local invalidation state 781 // map cache when an ID is unregistered. 782 TEST_F(SyncInvalidationListenerTest, UnregisterCleansUpStateMapCache) { 783 const ObjectId& id = kBookmarksId_; 784 listener_.Ready(fake_invalidation_client_); 785 786 EXPECT_TRUE(GetSavedInvalidations().empty()); 787 FireInvalidate(id, 1, "hello"); 788 EXPECT_EQ(1U, GetSavedInvalidations().size()); 789 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id)); 790 FireInvalidate(kPreferencesId_, 2, "world"); 791 EXPECT_EQ(2U, GetSavedInvalidations().size()); 792 793 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id)); 794 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), kPreferencesId_)); 795 796 ObjectIdSet ids; 797 ids.insert(id); 798 listener_.UpdateRegisteredIds(ids); 799 EXPECT_EQ(1U, GetSavedInvalidations().size()); 800 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id)); 801 } 802 803 TEST_F(SyncInvalidationListenerTest, DuplicateInvaldiations_Simple) { 804 const ObjectId& id = kBookmarksId_; 805 listener_.Ready(fake_invalidation_client_); 806 807 // Send a stream of invalidations, including two copies of the second. 808 FireInvalidate(id, 1, "one"); 809 FireInvalidate(id, 2, "two"); 810 FireInvalidate(id, 3, "three"); 811 FireInvalidate(id, 2, "two"); 812 813 // Expect that the duplicate was discarded. 814 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 815 EXPECT_EQ(3U, list.GetSize()); 816 SingleObjectInvalidationSet::const_iterator it = list.begin(); 817 EXPECT_EQ(1, it->version()); 818 it++; 819 EXPECT_EQ(2, it->version()); 820 it++; 821 EXPECT_EQ(3, it->version()); 822 } 823 824 TEST_F(SyncInvalidationListenerTest, DuplicateInvalidations_NearBufferLimit) { 825 const size_t kPairsToSend = UnackedInvalidationSet::kMaxBufferedInvalidations; 826 const ObjectId& id = kBookmarksId_; 827 listener_.Ready(fake_invalidation_client_); 828 829 // We will have enough buffer space in the state tracker for all these 830 // invalidations only if duplicates are ignored. 831 for (size_t i = 0; i < kPairsToSend; ++i) { 832 FireInvalidate(id, i, "payload"); 833 FireInvalidate(id, i, "payload"); 834 } 835 836 // Expect that the state map ignored duplicates. 837 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 838 EXPECT_EQ(kPairsToSend, list.GetSize()); 839 EXPECT_FALSE(list.begin()->is_unknown_version()); 840 841 // Expect that all invalidations (including duplicates) were emitted. 842 EXPECT_EQ(kPairsToSend*2, GetInvalidationCount(id)); 843 844 // Acknowledge all invalidations to clear the internal state. 845 AcknowledgeAll(id); 846 EXPECT_TRUE(GetSavedInvalidationsForType(id).IsEmpty()); 847 } 848 849 TEST_F(SyncInvalidationListenerTest, DuplicateInvalidations_UnknownVersion) { 850 const ObjectId& id = kBookmarksId_; 851 listener_.Ready(fake_invalidation_client_); 852 853 FireInvalidateUnknownVersion(id); 854 FireInvalidateUnknownVersion(id); 855 856 { 857 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 858 EXPECT_EQ(1U, list.GetSize()); 859 } 860 861 // Acknowledge the second. There should be no effect on the stored list. 862 ASSERT_EQ(2U, GetInvalidationCount(id)); 863 AcknowledgeNthInvalidation(id, 1); 864 { 865 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 866 EXPECT_EQ(1U, list.GetSize()); 867 } 868 869 // Acknowledge the first. This should remove the invalidation from the list. 870 ASSERT_EQ(2U, GetInvalidationCount(id)); 871 AcknowledgeNthInvalidation(id, 0); 872 { 873 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 874 EXPECT_EQ(0U, list.GetSize()); 875 } 876 } 877 878 // Make sure that acknowledgements erase items from the local store. 879 TEST_F(SyncInvalidationListenerTest, AcknowledgementsCleanUpStateMapCache) { 880 const ObjectId& id = kBookmarksId_; 881 listener_.Ready(fake_invalidation_client_); 882 883 EXPECT_TRUE(GetSavedInvalidations().empty()); 884 FireInvalidate(id, 10, "hello"); 885 FireInvalidate(id, 20, "world"); 886 FireInvalidateUnknownVersion(id); 887 888 // Expect that all three invalidations have been saved to permanent storage. 889 { 890 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 891 ASSERT_EQ(3U, list.GetSize()); 892 EXPECT_TRUE(list.begin()->is_unknown_version()); 893 EXPECT_EQ(20, list.back().version()); 894 } 895 896 // Acknowledge the second sent invaldiation (version 20) and verify it was 897 // removed from storage. 898 AcknowledgeNthInvalidation(id, 1); 899 { 900 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 901 ASSERT_EQ(2U, list.GetSize()); 902 EXPECT_TRUE(list.begin()->is_unknown_version()); 903 EXPECT_EQ(10, list.back().version()); 904 } 905 906 // Acknowledge the last sent invalidation (unknown version) and verify it was 907 // removed from storage. 908 AcknowledgeNthInvalidation(id, 2); 909 { 910 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 911 ASSERT_EQ(1U, list.GetSize()); 912 EXPECT_FALSE(list.begin()->is_unknown_version()); 913 EXPECT_EQ(10, list.back().version()); 914 } 915 } 916 917 // Make sure that drops erase items from the local store. 918 TEST_F(SyncInvalidationListenerTest, DropsCleanUpStateMapCache) { 919 const ObjectId& id = kBookmarksId_; 920 listener_.Ready(fake_invalidation_client_); 921 922 EXPECT_TRUE(GetSavedInvalidations().empty()); 923 FireInvalidate(id, 10, "hello"); 924 FireInvalidate(id, 20, "world"); 925 FireInvalidateUnknownVersion(id); 926 927 // Expect that all three invalidations have been saved to permanent storage. 928 { 929 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 930 ASSERT_EQ(3U, list.GetSize()); 931 EXPECT_TRUE(list.begin()->is_unknown_version()); 932 EXPECT_EQ(20, list.back().version()); 933 } 934 935 // Drop the second sent invalidation (version 20) and verify it was removed 936 // from storage. Also verify we still have an unknown version invalidation. 937 DropNthInvalidation(id, 1); 938 { 939 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 940 ASSERT_EQ(2U, list.GetSize()); 941 EXPECT_TRUE(list.begin()->is_unknown_version()); 942 EXPECT_EQ(10, list.back().version()); 943 } 944 945 // Drop the remaining invalidation. Verify an unknown version is all that 946 // remains. 947 DropNthInvalidation(id, 0); 948 { 949 SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id); 950 ASSERT_EQ(1U, list.GetSize()); 951 EXPECT_TRUE(list.begin()->is_unknown_version()); 952 } 953 954 // Announce that the delegate has recovered from the drop. Verify no 955 // invalidations remain saved. 956 RecoverFromDropEvent(id); 957 EXPECT_TRUE(GetSavedInvalidationsForType(id).IsEmpty()); 958 959 RecoverFromDropEvent(id); 960 } 961 962 // Without readying the client, disable notifications, then enable 963 // them. The listener should still think notifications are disabled. 964 TEST_F(SyncInvalidationListenerTest, EnableNotificationsNotReady) { 965 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, 966 GetInvalidatorState()); 967 968 DisableNotifications( 969 notifier::TRANSIENT_NOTIFICATION_ERROR); 970 971 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 972 973 DisableNotifications(notifier::NOTIFICATION_CREDENTIALS_REJECTED); 974 975 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 976 977 EnableNotifications(); 978 979 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 980 } 981 982 // Enable notifications then Ready the invalidation client. The 983 // delegate should then be ready. 984 TEST_F(SyncInvalidationListenerTest, EnableNotificationsThenReady) { 985 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 986 987 EnableNotifications(); 988 989 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 990 991 listener_.Ready(fake_invalidation_client_); 992 993 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 994 } 995 996 // Ready the invalidation client then enable notifications. The 997 // delegate should then be ready. 998 TEST_F(SyncInvalidationListenerTest, ReadyThenEnableNotifications) { 999 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 1000 1001 listener_.Ready(fake_invalidation_client_); 1002 1003 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState()); 1004 1005 EnableNotifications(); 1006 1007 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 1008 } 1009 1010 // Enable notifications and ready the client. Then disable 1011 // notifications with an auth error and re-enable notifications. The 1012 // delegate should go into an auth error mode and then back out. 1013 TEST_F(SyncInvalidationListenerTest, PushClientAuthError) { 1014 EnableNotifications(); 1015 listener_.Ready(fake_invalidation_client_); 1016 1017 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 1018 1019 DisableNotifications( 1020 notifier::NOTIFICATION_CREDENTIALS_REJECTED); 1021 1022 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 1023 1024 EnableNotifications(); 1025 1026 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 1027 } 1028 1029 // Enable notifications and ready the client. Then simulate an auth 1030 // error from the invalidation client. Simulate some notification 1031 // events, then re-ready the client. The delegate should go into an 1032 // auth error mode and come out of it only after the client is ready. 1033 TEST_F(SyncInvalidationListenerTest, InvalidationClientAuthError) { 1034 EnableNotifications(); 1035 listener_.Ready(fake_invalidation_client_); 1036 1037 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 1038 1039 listener_.InformError( 1040 fake_invalidation_client_, 1041 invalidation::ErrorInfo( 1042 invalidation::ErrorReason::AUTH_FAILURE, 1043 false /* is_transient */, 1044 "auth error", 1045 invalidation::ErrorContext())); 1046 1047 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 1048 1049 DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR); 1050 1051 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 1052 1053 DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR); 1054 1055 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 1056 1057 EnableNotifications(); 1058 1059 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState()); 1060 1061 listener_.Ready(fake_invalidation_client_); 1062 1063 EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState()); 1064 } 1065 1066 // A variant of SyncInvalidationListenerTest that starts with some initial 1067 // state. We make not attempt to abstract away the contents of this state. The 1068 // tests that make use of this harness depend on its implementation details. 1069 class SyncInvalidationListenerTest_WithInitialState 1070 : public SyncInvalidationListenerTest { 1071 public: 1072 virtual void SetUp() { 1073 UnackedInvalidationSet bm_state(kBookmarksId_); 1074 UnackedInvalidationSet ext_state(kExtensionsId_); 1075 1076 Invalidation bm_unknown = Invalidation::InitUnknownVersion(kBookmarksId_); 1077 Invalidation bm_v100 = Invalidation::Init(kBookmarksId_, 100, "hundred"); 1078 bm_state.Add(bm_unknown); 1079 bm_state.Add(bm_v100); 1080 1081 Invalidation ext_v10 = Invalidation::Init(kExtensionsId_, 10, "ten"); 1082 Invalidation ext_v20 = Invalidation::Init(kExtensionsId_, 20, "twenty"); 1083 ext_state.Add(ext_v10); 1084 ext_state.Add(ext_v20); 1085 1086 initial_state.insert(std::make_pair(kBookmarksId_, bm_state)); 1087 initial_state.insert(std::make_pair(kExtensionsId_, ext_state)); 1088 1089 fake_tracker_.SetSavedInvalidations(initial_state); 1090 1091 SyncInvalidationListenerTest::SetUp(); 1092 } 1093 1094 UnackedInvalidationsMap initial_state; 1095 }; 1096 1097 // Verify that saved invalidations are forwarded when handlers register. 1098 TEST_F(SyncInvalidationListenerTest_WithInitialState, 1099 ReceiveSavedInvalidations) { 1100 EnableNotifications(); 1101 listener_.Ready(fake_invalidation_client_); 1102 1103 EXPECT_THAT(initial_state, test_util::Eq(GetSavedInvalidations())); 1104 1105 ASSERT_EQ(2U, GetInvalidationCount(kBookmarksId_)); 1106 EXPECT_EQ(100, GetVersion(kBookmarksId_)); 1107 1108 ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_)); 1109 1110 FireInvalidate(kExtensionsId_, 30, "thirty"); 1111 1112 ObjectIdSet ids = GetRegisteredIds(); 1113 ids.insert(kExtensionsId_); 1114 listener_.UpdateRegisteredIds(ids); 1115 1116 ASSERT_EQ(3U, GetInvalidationCount(kExtensionsId_)); 1117 EXPECT_EQ(30, GetVersion(kExtensionsId_)); 1118 } 1119 1120 } // namespace 1121 1122 } // namespace syncer 1123