// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/sync/glue/sync_backend_host.h" #include #include "base/location.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/synchronization/waitable_event.h" #include "base/test/test_timeouts.h" #include "chrome/browser/sync/invalidations/invalidator_storage.h" #include "chrome/browser/sync/sync_prefs.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread.h" #include "google/cacheinvalidation/include/types.h" #include "googleurl/src/gurl.h" #include "net/url_request/test_url_fetcher_factory.h" #include "sync/internal_api/public/base/model_type.h" #include "sync/internal_api/public/engine/model_safe_worker.h" #include "sync/internal_api/public/sync_manager_factory.h" #include "sync/internal_api/public/test/fake_sync_manager.h" #include "sync/internal_api/public/util/experiments.h" #include "sync/notifier/invalidator_state.h" #include "sync/notifier/object_id_state_map_test_util.h" #include "sync/protocol/encryption.pb.h" #include "sync/protocol/sync_protocol_error.h" #include "sync/util/test_unrecoverable_error_handler.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using content::BrowserThread; using syncer::FakeSyncManager; using syncer::SyncManager; using ::testing::InvokeWithoutArgs; using ::testing::StrictMock; using ::testing::_; namespace browser_sync { namespace { ACTION_P(Signal, event) { event->Signal(); } void SignalEvent(base::WaitableEvent* event) { event->Signal(); } static void QuitMessageLoop() { MessageLoop::current()->Quit(); } class MockSyncFrontend : public SyncFrontend { public: virtual ~MockSyncFrontend() {} MOCK_METHOD1(OnInvalidatorStateChange, void(syncer::InvalidatorState)); MOCK_METHOD2(OnIncomingInvalidation, void(const syncer::ObjectIdStateMap&, syncer::IncomingInvalidationSource)); MOCK_METHOD2(OnBackendInitialized, void(const syncer::WeakHandle&, bool)); MOCK_METHOD0(OnSyncCycleCompleted, void()); MOCK_METHOD1(OnConnectionStatusChange, void(syncer::ConnectionStatus status)); MOCK_METHOD0(OnStopSyncingPermanently, void()); MOCK_METHOD0(OnClearServerDataSucceeded, void()); MOCK_METHOD0(OnClearServerDataFailed, void()); MOCK_METHOD2(OnPassphraseRequired, void(syncer::PassphraseRequiredReason, const sync_pb::EncryptedData&)); MOCK_METHOD0(OnPassphraseAccepted, void()); MOCK_METHOD2(OnEncryptedTypesChanged, void(syncer::ModelTypeSet, bool)); MOCK_METHOD0(OnEncryptionComplete, void()); MOCK_METHOD1(OnMigrationNeededForTypes, void(syncer::ModelTypeSet)); MOCK_METHOD1(OnExperimentsChanged, void(const syncer::Experiments&)); MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError& sync_error)); MOCK_METHOD0(OnSyncConfigureRetry, void()); }; class FakeSyncManagerFactory : public syncer::SyncManagerFactory { public: FakeSyncManagerFactory() : fake_manager_(NULL) {} virtual ~FakeSyncManagerFactory() {} // SyncManagerFactory implementation. Called on the sync thread. virtual scoped_ptr CreateSyncManager( std::string name) OVERRIDE { DCHECK(!fake_manager_); fake_manager_ = new FakeSyncManager(initial_sync_ended_types_, progress_marker_types_, configure_fail_types_); return scoped_ptr(fake_manager_); } // Returns NULL until CreateSyncManager() is called on the sync // thread. Called on the main thread, but only after // OnBackendInitialized() is called (which is strictly after // CreateSyncManager is called on the sync thread). FakeSyncManager* fake_manager() { return fake_manager_; } void set_initial_sync_ended_types(syncer::ModelTypeSet types) { initial_sync_ended_types_ = types; } void set_progress_marker_types(syncer::ModelTypeSet types) { progress_marker_types_ = types; } void set_configure_fail_types(syncer::ModelTypeSet types) { configure_fail_types_ = types; } private: syncer::ModelTypeSet initial_sync_ended_types_; syncer::ModelTypeSet progress_marker_types_; syncer::ModelTypeSet configure_fail_types_; FakeSyncManager* fake_manager_; }; class SyncBackendHostTest : public testing::Test { protected: SyncBackendHostTest() : ui_thread_(BrowserThread::UI, &ui_loop_), io_thread_(BrowserThread::IO), fake_manager_(NULL) {} virtual ~SyncBackendHostTest() {} virtual void SetUp() OVERRIDE { io_thread_.StartIOThread(); profile_.reset(new TestingProfile()); profile_->CreateRequestContext(); sync_prefs_.reset(new SyncPrefs(profile_->GetPrefs())); invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); backend_.reset(new SyncBackendHost( profile_->GetDebugName(), profile_.get(), sync_prefs_->AsWeakPtr(), invalidator_storage_->AsWeakPtr())); credentials_.email = "user@example.com"; credentials_.sync_token = "sync_token"; // NOTE: We can't include Passwords or Typed URLs due to the Sync Backend // Registrar removing them if it can't find their model workers. enabled_types_.Put(syncer::BOOKMARKS); enabled_types_.Put(syncer::NIGORI); enabled_types_.Put(syncer::PREFERENCES); enabled_types_.Put(syncer::SESSIONS); enabled_types_.Put(syncer::SEARCH_ENGINES); enabled_types_.Put(syncer::AUTOFILL); } virtual void TearDown() OVERRIDE { if (backend_.get()) { backend_->StopSyncingForShutdown(); backend_->Shutdown(false); } backend_.reset(); sync_prefs_.reset(); invalidator_storage_.reset(); profile_.reset(); // Pump messages posted by the sync thread (which may end up // posting on the IO thread). ui_loop_.RunAllPending(); io_thread_.Stop(); // Pump any messages posted by the IO thread. ui_loop_.RunAllPending(); } // Synchronously initializes the backend. void InitializeBackend() { EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, true)). WillOnce(InvokeWithoutArgs(QuitMessageLoop)); backend_->Initialize(&mock_frontend_, syncer::WeakHandle(), GURL(""), credentials_, true, &fake_manager_factory_, &handler_, NULL); ui_loop_.PostDelayedTask(FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout()); ui_loop_.Run(); // |fake_manager_factory_|'s fake_manager() is set on the sync // thread, but we can rely on the message loop barriers to // guarantee that we see the updated value. fake_manager_ = fake_manager_factory_.fake_manager(); DCHECK(fake_manager_); } // Synchronously configures the backend's datatypes. void ConfigureDataTypes(syncer::ModelTypeSet types_to_add, syncer::ModelTypeSet types_to_remove) { types_to_add.PutAll(syncer::ControlTypes()); backend_->ConfigureDataTypes( syncer::CONFIGURE_REASON_RECONFIGURATION, types_to_add, types_to_remove, base::Bind(&SyncBackendHostTest::DownloadReady, base::Unretained(this)), base::Bind(&SyncBackendHostTest::OnDownloadRetry, base::Unretained(this))); ui_loop_.PostDelayedTask(FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout()); ui_loop_.Run(); } protected: void DownloadReady(syncer::ModelTypeSet types) { MessageLoop::current()->Quit(); } void OnDownloadRetry() { NOTIMPLEMENTED(); } MessageLoop ui_loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread io_thread_; StrictMock mock_frontend_; syncer::SyncCredentials credentials_; syncer::TestUnrecoverableErrorHandler handler_; scoped_ptr profile_; scoped_ptr sync_prefs_; scoped_ptr invalidator_storage_; scoped_ptr backend_; FakeSyncManager* fake_manager_; FakeSyncManagerFactory fake_manager_factory_; syncer::ModelTypeSet enabled_types_; }; // Test basic initialization with no initial types (first time initialization). // Only the nigori should be configured. TEST_F(SyncBackendHostTest, InitShutdown) { InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( syncer::ControlTypes())); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals( syncer::ControlTypes())); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( syncer::ControlTypes()).Empty()); } // Test first time sync scenario. All types should be properly configured. TEST_F(SyncBackendHostTest, FirstTimeSync) { InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( syncer::ControlTypes())); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals( syncer::ControlTypes())); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( syncer::ControlTypes()).Empty()); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll( Difference(enabled_types_, syncer::ControlTypes()))); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // Test the restart after setting up sync scenario. No enabled types should be // downloaded or cleaned. TEST_F(SyncBackendHostTest, Restart) { sync_prefs_->SetSyncSetupCompleted(); syncer::ModelTypeSet all_but_nigori = enabled_types_; fake_manager_factory_.set_progress_marker_types(enabled_types_); fake_manager_factory_.set_initial_sync_ended_types(enabled_types_); InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty()); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty()); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // Test a sync restart scenario where some types had never finished configuring. // The partial types should be purged, then reconfigured properly. TEST_F(SyncBackendHostTest, PartialTypes) { sync_prefs_->SetSyncSetupCompleted(); // Set sync manager behavior before passing it down. All types have progress // markers, but nigori and bookmarks are missing initial sync ended. syncer::ModelTypeSet partial_types(syncer::NIGORI, syncer::BOOKMARKS); syncer::ModelTypeSet full_types = Difference(enabled_types_, partial_types); fake_manager_factory_.set_progress_marker_types(enabled_types_); fake_manager_factory_.set_initial_sync_ended_types(full_types); // Bringing up the backend should purge all partial types, then proceed to // download the Nigori. InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( syncer::ModelTypeSet(syncer::NIGORI))); EXPECT_TRUE(fake_manager_->GetAndResetCleanedTypes().HasAll(partial_types)); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals( Union(full_types, syncer::ModelTypeSet(syncer::NIGORI)))); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Equals( Difference(partial_types, syncer::ModelTypeSet(syncer::NIGORI)))); // Now do the actual configuration, which should download and apply bookmarks. ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( partial_types)); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // Test the behavior when we lose the sync db. Although we already have types // enabled, we should re-download all of them because we lost their data. TEST_F(SyncBackendHostTest, LostDB) { sync_prefs_->SetSyncSetupCompleted(); // Initialization should fetch the Nigori node. Everything else should be // left untouched. InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( syncer::ModelTypeSet(syncer::ControlTypes()))); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals( syncer::ModelTypeSet(syncer::ControlTypes()))); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Equals( Difference(enabled_types_, syncer::ControlTypes()))); // The database was empty, so any cleaning is entirely optional. We want to // reset this value before running the next part of the test, though. fake_manager_->GetAndResetCleanedTypes(); // The actual configuration should redownload and apply all the enabled types. ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll( Difference(enabled_types_, syncer::ControlTypes()))); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } TEST_F(SyncBackendHostTest, DisableTypes) { // Simulate first time sync. InitializeBackend(); fake_manager_->GetAndResetCleanedTypes(); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( enabled_types_)); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); // Then disable two datatypes. syncer::ModelTypeSet disabled_types(syncer::BOOKMARKS, syncer::SEARCH_ENGINES); syncer::ModelTypeSet old_types = enabled_types_; enabled_types_.RemoveAll(disabled_types); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); // Only those datatypes disabled should be cleaned. Nothing should be // downloaded. EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty()); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), old_types).Equals(disabled_types)); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } TEST_F(SyncBackendHostTest, AddTypes) { // Simulate first time sync. InitializeBackend(); fake_manager_->GetAndResetCleanedTypes(); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( enabled_types_)); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); // Then add two datatypes. syncer::ModelTypeSet new_types(syncer::EXTENSIONS, syncer::APPS); enabled_types_.PutAll(new_types); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); // Only those datatypes added should be downloaded (plus nigori). Nothing // should be cleaned aside from the disabled types. EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( Union(new_types, syncer::ModelTypeSet(syncer::NIGORI)))); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // And and disable in the same configuration. TEST_F(SyncBackendHostTest, AddDisableTypes) { // Simulate first time sync. InitializeBackend(); fake_manager_->GetAndResetCleanedTypes(); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( enabled_types_)); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); // Then add two datatypes. syncer::ModelTypeSet old_types = enabled_types_; syncer::ModelTypeSet disabled_types(syncer::BOOKMARKS, syncer::SEARCH_ENGINES); syncer::ModelTypeSet new_types(syncer::EXTENSIONS, syncer::APPS); enabled_types_.PutAll(new_types); enabled_types_.RemoveAll(disabled_types); ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); // Only those datatypes added should be downloaded (plus nigori). Nothing // should be cleaned aside from the disabled types. EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( Union(new_types, syncer::ModelTypeSet(syncer::NIGORI)))); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), old_types).Equals(disabled_types)); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( old_types).Equals(disabled_types)); } // Test restarting the browser to newly supported datatypes. The new datatypes // should be downloaded on the configuration after backend initialization. TEST_F(SyncBackendHostTest, NewlySupportedTypes) { sync_prefs_->SetSyncSetupCompleted(); // Set sync manager behavior before passing it down. All types have progress // markers and initial sync ended except the new types. syncer::ModelTypeSet old_types = enabled_types_; fake_manager_factory_.set_progress_marker_types(old_types); fake_manager_factory_.set_initial_sync_ended_types(old_types); syncer::ModelTypeSet new_types(syncer::APP_SETTINGS, syncer::EXTENSION_SETTINGS); enabled_types_.PutAll(new_types); // Does nothing. InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty()); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), old_types).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(old_types)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Equals(new_types)); // Downloads and applies the new types. ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( Union(new_types, syncer::ModelTypeSet(syncer::NIGORI)))); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // Test the newly supported types scenario, but with the presence of partial // types as well. Both partial and newly supported types should be downloaded // the configuration. TEST_F(SyncBackendHostTest, NewlySupportedTypesWithPartialTypes) { sync_prefs_->SetSyncSetupCompleted(); // Set sync manager behavior before passing it down. All types have progress // markers and initial sync ended except the new types. syncer::ModelTypeSet old_types = enabled_types_; syncer::ModelTypeSet partial_types(syncer::NIGORI, syncer::BOOKMARKS); syncer::ModelTypeSet full_types = Difference(enabled_types_, partial_types); fake_manager_factory_.set_progress_marker_types(old_types); fake_manager_factory_.set_initial_sync_ended_types(full_types); syncer::ModelTypeSet new_types(syncer::APP_SETTINGS, syncer::EXTENSION_SETTINGS); enabled_types_.PutAll(new_types); // Purge the partial types. The nigori will be among the purged types, but // the syncer will re-download it by the time the initialization is complete. InitializeBackend(); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( syncer::ModelTypeSet(syncer::NIGORI))); EXPECT_TRUE(fake_manager_->GetAndResetCleanedTypes().HasAll(partial_types)); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals( syncer::Union(full_types, syncer::ModelTypeSet(syncer::NIGORI)))); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Equals(Union(new_types, Difference( partial_types, syncer::ModelTypeSet(syncer::NIGORI))))); // Downloads and applies the new types and partial types (which includes // nigori anyways). ConfigureDataTypes(enabled_types_, Difference(syncer::ModelTypeSet::All(), enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( Union(new_types, partial_types))); EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), enabled_types_).Empty()); EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetAndResetEnabledTypes().Equals(enabled_types_)); EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( enabled_types_).Empty()); } // Register for some IDs and trigger an invalidation. This should // propagate all the way to the frontend. TEST_F(SyncBackendHostTest, Invalidate) { InitializeBackend(); syncer::ObjectIdSet ids; ids.insert(invalidation::ObjectId(1, "id1")); ids.insert(invalidation::ObjectId(2, "id2")); const syncer::ObjectIdStateMap& id_state_map = syncer::ObjectIdSetToStateMap(ids, "payload"); EXPECT_CALL( mock_frontend_, OnIncomingInvalidation(id_state_map, syncer::REMOTE_INVALIDATION)) .WillOnce(InvokeWithoutArgs(QuitMessageLoop)); backend_->UpdateRegisteredInvalidationIds(ids); fake_manager_->Invalidate(id_state_map, syncer::REMOTE_INVALIDATION); ui_loop_.PostDelayedTask( FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout()); ui_loop_.Run(); } // Register for some IDs and update the invalidator state. This // should propagate all the way to the frontend. TEST_F(SyncBackendHostTest, UpdateInvalidatorState) { InitializeBackend(); EXPECT_CALL(mock_frontend_, OnInvalidatorStateChange(syncer::INVALIDATIONS_ENABLED)) .WillOnce(InvokeWithoutArgs(QuitMessageLoop)); syncer::ObjectIdSet ids; ids.insert(invalidation::ObjectId(3, "id3")); backend_->UpdateRegisteredInvalidationIds(ids); fake_manager_->UpdateInvalidatorState(syncer::INVALIDATIONS_ENABLED); ui_loop_.PostDelayedTask( FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout()); ui_loop_.Run(); } // Call StopSyncingForShutdown() on the backend and fire some invalidations // before calling Shutdown(). Then start up and shut down the backend again. // Those notifications shouldn't propagate to the frontend. TEST_F(SyncBackendHostTest, InvalidationsAfterStopSyncingForShutdown) { InitializeBackend(); syncer::ObjectIdSet ids; ids.insert(invalidation::ObjectId(5, "id5")); backend_->UpdateRegisteredInvalidationIds(ids); backend_->StopSyncingForShutdown(); // Should not trigger anything. fake_manager_->UpdateInvalidatorState(syncer::TRANSIENT_INVALIDATION_ERROR); fake_manager_->UpdateInvalidatorState(syncer::INVALIDATIONS_ENABLED); const syncer::ObjectIdStateMap& id_state_map = syncer::ObjectIdSetToStateMap(ids, "payload"); fake_manager_->Invalidate(id_state_map, syncer::REMOTE_INVALIDATION); // Make sure the above calls take effect before we continue. fake_manager_->WaitForSyncThread(); backend_->Shutdown(false); backend_.reset(); TearDown(); SetUp(); } } // namespace } // namespace browser_sync