blob: 945de64da0d68eaabc0a00cafeacd30fa9c4200c [file] [log] [blame]
// 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 <cstddef>
#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<syncer::JsBackend>&, 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<SyncManager> 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<SyncManager>(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<syncer::JsEventHandler>(),
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<MockSyncFrontend> mock_frontend_;
syncer::SyncCredentials credentials_;
syncer::TestUnrecoverableErrorHandler handler_;
scoped_ptr<TestingProfile> profile_;
scoped_ptr<SyncPrefs> sync_prefs_;
scoped_ptr<InvalidatorStorage> invalidator_storage_;
scoped_ptr<SyncBackendHost> 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