blob: 0bc0073d0ad9adf947623637ae1d858dad1205ed [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/service/glue/sync_engine_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "components/os_crypt/async/browser/test_utils.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/data_type.h"
#include "components/sync/base/features.h"
#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
#include "components/sync/engine/net/http_bridge.h"
#include "components/sync/engine/sync_engine_host.h"
#include "components/sync/engine/sync_manager_factory.h"
#include "components/sync/protocol/sync_enums.pb.h"
#include "components/sync/protocol/sync_invalidations_payload.pb.h"
#include "components/sync/service/active_devices_provider.h"
#include "components/sync/service/glue/sync_transport_data_prefs.h"
#include "components/sync/test/fake_sync_manager.h"
#include "components/sync/test/mock_sync_invalidations_service.h"
#include "google_apis/gaia/gaia_id.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::ByMove;
using testing::NiceMock;
using testing::Return;
using testing::Sequence;
namespace syncer {
namespace {
static const base::FilePath::CharType kTestSyncDir[] =
FILE_PATH_LITERAL("sync-test");
constexpr GaiaId::Literal kTestGaiaId("test_gaia_id");
constexpr char kTestCacheGuid[] = "test_cache_guid";
constexpr char kTestBirthday[] = "test_birthday";
class MockSyncEngineHost : public SyncEngineHost {
public:
MOCK_METHOD(void,
OnEngineInitialized,
(bool success, bool is_first_time_sync_configure),
(override));
MOCK_METHOD(void,
OnSyncCycleCompleted,
(const SyncCycleSnapshot& snapshot),
(override));
MOCK_METHOD(void, OnProtocolEvent, (const ProtocolEvent& event), (override));
MOCK_METHOD(void,
OnConnectionStatusChange,
(ConnectionStatus status),
(override));
MOCK_METHOD(void, OnMigrationNeededForTypes, (DataTypeSet types), (override));
MOCK_METHOD(void,
OnActionableProtocolError,
(const SyncProtocolError& error),
(override));
MOCK_METHOD(void, OnBackedOffTypesChanged, (), (override));
MOCK_METHOD(void, OnInvalidationStatusChanged, (), (override));
MOCK_METHOD(void, OnNewInvalidatedDataTypes, (), (override));
};
class FakeSyncManagerFactory : public SyncManagerFactory {
public:
FakeSyncManagerFactory(
raw_ptr<FakeSyncManager>* fake_manager,
network::NetworkConnectionTracker* network_connection_tracker)
: SyncManagerFactory(network_connection_tracker),
fake_manager_(fake_manager) {
*fake_manager_ = nullptr;
}
~FakeSyncManagerFactory() override = default;
// SyncManagerFactory implementation. Called on the sync thread.
std::unique_ptr<SyncManager> CreateSyncManager(
const std::string& /* name */) override {
*fake_manager_ =
new FakeSyncManager(initial_sync_ended_types_, progress_marker_types_,
configure_fail_types_);
return std::unique_ptr<SyncManager>(*fake_manager_);
}
void set_initial_sync_ended_types(DataTypeSet types) {
initial_sync_ended_types_ = types;
}
void set_progress_marker_types(DataTypeSet types) {
progress_marker_types_ = types;
}
void set_configure_fail_types(DataTypeSet types) {
configure_fail_types_ = types;
}
private:
DataTypeSet initial_sync_ended_types_;
DataTypeSet progress_marker_types_;
DataTypeSet configure_fail_types_;
const raw_ptr<raw_ptr<FakeSyncManager>> fake_manager_;
};
class MockActiveDevicesProvider : public ActiveDevicesProvider {
public:
MockActiveDevicesProvider() = default;
~MockActiveDevicesProvider() override = default;
MOCK_METHOD(void,
SetActiveDevicesChangedCallback,
(ActiveDevicesProvider::ActiveDevicesChangedCallback),
(override));
MOCK_METHOD(ActiveDevicesInvalidationInfo,
CalculateInvalidationInfo,
(const std::string&),
(const override));
};
std::unique_ptr<HttpPostProviderFactory> CreateHttpBridgeFactory() {
return std::make_unique<HttpBridgeFactory>(
/*user_agent=*/"",
/*pending_url_loader_factory=*/nullptr);
}
class SyncEngineImplTest : public testing::Test {
protected:
SyncEngineImplTest() = default;
~SyncEngineImplTest() override = default;
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
SyncTransportDataPrefs::RegisterProfilePrefs(pref_service_.registry());
scoped_refptr<base::SequencedTaskRunner> sync_task_runner =
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
auto mock_active_devices_provider =
std::make_unique<NiceMock<MockActiveDevicesProvider>>();
ON_CALL(*mock_active_devices_provider.get(), CalculateInvalidationInfo)
.WillByDefault(Return(
ByMove(ActiveDevicesInvalidationInfo::CreateUninitialized())));
backend_ = std::make_unique<SyncEngineImpl>(
"fakeDebugName", &mock_sync_invalidations_service_,
std::move(mock_active_devices_provider),
std::make_unique<SyncTransportDataPrefs>(
&pref_service_, signin::GaiaIdHash::FromGaiaId(kTestGaiaId)),
temp_dir_.GetPath().Append(base::FilePath(kTestSyncDir)),
std::move(sync_task_runner));
fake_manager_factory_ = std::make_unique<FakeSyncManagerFactory>(
&fake_manager_, network::TestNetworkConnectionTracker::GetInstance());
// These types are always implicitly enabled.
enabled_types_.PutAll(ControlTypes());
// 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(BOOKMARKS);
enabled_types_.Put(PREFERENCES);
enabled_types_.Put(SESSIONS);
enabled_types_.Put(SEARCH_ENGINES);
enabled_types_.Put(AUTOFILL);
}
void TearDown() override {
if (backend_) {
ShutdownBackend(ShutdownReason::BROWSER_SHUTDOWN_AND_KEEP_DATA);
}
// Pump messages posted by the sync thread.
base::RunLoop().RunUntilIdle();
}
// Synchronously initializes the backend.
void InitializeBackend(bool expect_success = true,
const GaiaId& gaia_id = kTestGaiaId) {
SyncEngine::InitParams params;
params.host = &mock_host_;
params.http_factory_getter = base::BindOnce(&CreateHttpBridgeFactory);
params.authenticated_account_info.gaia = gaia_id;
params.authenticated_account_info.account_id =
CoreAccountId::FromGaiaId(gaia_id);
params.sync_manager_factory = std::move(fake_manager_factory_);
if (base::FeatureList::IsEnabled(syncer::kSyncUseOsCryptAsync)) {
std::unique_ptr<os_crypt_async::OSCryptAsync> os_cryp_async =
os_crypt_async::GetTestOSCryptAsyncForTesting();
base::test::TestFuture<os_crypt_async::Encryptor> future;
os_cryp_async->GetInstance(future.GetCallback());
params.encryptor =
std::make_unique<os_crypt_async::Encryptor>(future.Take());
}
EXPECT_CALL(mock_host_, OnEngineInitialized(expect_success, _))
.WillOnce(
testing::InvokeWithoutArgs(this, &SyncEngineImplTest::QuitRunLoop));
backend_->Initialize(std::move(params));
PumpSyncThread();
// `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.
DCHECK(fake_manager_);
if (expect_success) {
EXPECT_TRUE(engine_types_.empty());
engine_types_ = fake_manager_->GetConnectedTypes();
ON_CALL(mock_sync_invalidations_service_, GetInterestedDataTypes)
.WillByDefault(Return(engine_types_));
}
}
void ShutdownBackend(ShutdownReason reason) {
DCHECK(backend_);
backend_->StopSyncingForShutdown();
// Reset `fake_manager_` to avoid dangling pointer.
fake_manager_ = nullptr;
backend_->Shutdown(reason);
backend_.reset();
}
// Synchronously configures the backend's datatypes.
DataTypeSet ConfigureDataTypes() {
return ConfigureDataTypesWithUnready(DataTypeSet());
}
DataTypeSet ConfigureDataTypesWithUnready(DataTypeSet unready_types) {
DataTypeConfigurer::ConfigureParams params;
params.reason = CONFIGURE_REASON_RECONFIGURATION;
DataTypeSet enabled_types = Difference(enabled_types_, unready_types);
params.to_download = Difference(enabled_types, engine_types_);
if (!params.to_download.empty()) {
params.to_download.Put(NIGORI);
}
params.ready_task = base::BindOnce(&SyncEngineImplTest::DownloadReady,
base::Unretained(this));
DataTypeSet ready_types = Difference(enabled_types, params.to_download);
backend_->ConfigureDataTypes(std::move(params));
PumpSyncThread();
return ready_types;
}
protected:
void DownloadReady(DataTypeSet succeeded_types, DataTypeSet failed_types) {
engine_types_.PutAll(succeeded_types);
backend_->StartSyncingWithServer();
QuitRunLoop();
}
void QuitRunLoop() { std::move(quit_loop_).Run(); }
void PumpSyncThread() {
base::RunLoop run_loop;
quit_loop_ = run_loop.QuitClosure();
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&SyncEngineImplTest::QuitRunLoop,
weak_ptr_factory_.GetWeakPtr()),
TestTimeouts::action_timeout());
run_loop.Run();
}
base::test::TaskEnvironment task_environment_;
base::ScopedTempDir temp_dir_;
TestingPrefServiceSimple pref_service_;
NiceMock<MockSyncEngineHost> mock_host_;
std::unique_ptr<SyncEngineImpl> backend_;
std::unique_ptr<FakeSyncManagerFactory> fake_manager_factory_;
raw_ptr<FakeSyncManager> fake_manager_ = nullptr;
DataTypeSet engine_types_;
DataTypeSet enabled_types_;
base::OnceClosure quit_loop_;
NiceMock<MockSyncInvalidationsService> mock_sync_invalidations_service_;
base::WeakPtrFactory<SyncEngineImplTest> weak_ptr_factory_{this};
};
// Test basic initialization with no initial types (first time initialization).
// Only the nigori should be configured.
TEST_F(SyncEngineImplTest, InitShutdownWithStopSync) {
InitializeBackend();
EXPECT_EQ(ControlTypes(), fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(ControlTypes(), fake_manager_->InitialSyncEndedTypes());
ShutdownBackend(ShutdownReason::STOP_SYNC_AND_KEEP_DATA);
}
TEST_F(SyncEngineImplTest, InitShutdownWithDisableSync) {
InitializeBackend();
EXPECT_EQ(ControlTypes(), fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(ControlTypes(), fake_manager_->InitialSyncEndedTypes());
ShutdownBackend(ShutdownReason::DISABLE_SYNC_AND_CLEAR_DATA);
}
// Test first time sync scenario. All types should be properly configured.
TEST_F(SyncEngineImplTest, FirstTimeSync) {
InitializeBackend();
EXPECT_EQ(ControlTypes(), fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(ControlTypes(), fake_manager_->InitialSyncEndedTypes());
DataTypeSet ready_types = ConfigureDataTypes();
// Nigori is always downloaded so won't be ready.
EXPECT_EQ(Difference(ControlTypes(), {NIGORI}), ready_types);
EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll(
Difference(enabled_types_, ControlTypes())));
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
}
// Test the restart after setting up sync scenario. No enabled types should be
// downloaded.
TEST_F(SyncEngineImplTest, Restart) {
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_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
DataTypeSet ready_types = ConfigureDataTypes();
EXPECT_EQ(enabled_types_, ready_types);
EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().empty());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
}
TEST_F(SyncEngineImplTest, DisableTypes) {
// Simulate first time sync.
InitializeBackend();
DataTypeSet ready_types = ConfigureDataTypes();
// Nigori is always downloaded so won't be ready.
EXPECT_EQ(Difference(ControlTypes(), {NIGORI}), ready_types);
EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
// Then disable two datatypes.
DataTypeSet disabled_types = {BOOKMARKS, SEARCH_ENGINES};
enabled_types_.RemoveAll(disabled_types);
ready_types = ConfigureDataTypes();
// Only those datatypes disabled should be cleaned. Nothing should be
// downloaded.
EXPECT_EQ(enabled_types_, ready_types);
EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().empty());
}
TEST_F(SyncEngineImplTest, AddTypes) {
// Simulate first time sync.
InitializeBackend();
DataTypeSet ready_types = ConfigureDataTypes();
// Nigori is always downloaded so won't be ready.
EXPECT_EQ(Difference(ControlTypes(), {NIGORI}), ready_types);
EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
// Then add two datatypes.
DataTypeSet new_types = {EXTENSIONS, APPS};
enabled_types_.PutAll(new_types);
ready_types = ConfigureDataTypes();
// Only those datatypes added should be downloaded (plus nigori). Nothing
// should be cleaned aside from the disabled types.
new_types.Put(NIGORI);
EXPECT_EQ(Difference(enabled_types_, new_types), ready_types);
EXPECT_EQ(new_types, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
}
// And and disable in the same configuration.
TEST_F(SyncEngineImplTest, AddDisableTypes) {
// Simulate first time sync.
InitializeBackend();
DataTypeSet ready_types = ConfigureDataTypes();
// Nigori is always downloaded so won't be ready.
EXPECT_EQ(Difference(ControlTypes(), {NIGORI}), ready_types);
EXPECT_EQ(enabled_types_, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
// Then add two datatypes.
DataTypeSet disabled_types = {BOOKMARKS, SEARCH_ENGINES};
DataTypeSet new_types = {EXTENSIONS, APPS};
enabled_types_.PutAll(new_types);
enabled_types_.RemoveAll(disabled_types);
ready_types = ConfigureDataTypes();
// Only those datatypes added should be downloaded (plus nigori). Nothing
// should be cleaned aside from the disabled types.
new_types.Put(NIGORI);
EXPECT_EQ(Difference(enabled_types_, new_types), ready_types);
EXPECT_EQ(new_types, fake_manager_->GetAndResetDownloadedTypes());
}
// Test restarting the browser to newly supported datatypes. The new datatypes
// should be downloaded on the configuration after backend initialization.
TEST_F(SyncEngineImplTest, NewlySupportedTypes) {
// Set sync manager behavior before passing it down. All types have progress
// markers and initial sync ended except the new types.
DataTypeSet old_types = enabled_types_;
fake_manager_factory_->set_progress_marker_types(old_types);
fake_manager_factory_->set_initial_sync_ended_types(old_types);
DataTypeSet new_types = {APP_SETTINGS, EXTENSION_SETTINGS};
enabled_types_.PutAll(new_types);
// Does nothing.
InitializeBackend();
EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().empty());
EXPECT_EQ(old_types, fake_manager_->InitialSyncEndedTypes());
// Downloads and applies the new types (plus nigori).
DataTypeSet ready_types = ConfigureDataTypes();
new_types.Put(NIGORI);
EXPECT_EQ(Difference(old_types, {NIGORI}), ready_types);
EXPECT_EQ(new_types, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
}
// Verify that downloading control types only downloads those types that do
// not have initial sync ended set.
TEST_F(SyncEngineImplTest, DownloadControlTypes) {
// Set sync manager behavior before passing it down. Experiments and device
// info are new types without progress markers or initial sync ended, while
// all other types have been fully downloaded and applied.
DataTypeSet new_types = {NIGORI};
DataTypeSet old_types = Difference(enabled_types_, new_types);
fake_manager_factory_->set_progress_marker_types(old_types);
fake_manager_factory_->set_initial_sync_ended_types(old_types);
// Bringing up the backend should download the new types without downloading
// any old types.
InitializeBackend();
EXPECT_EQ(new_types, fake_manager_->GetAndResetDownloadedTypes());
EXPECT_EQ(enabled_types_, fake_manager_->InitialSyncEndedTypes());
}
// Fail to download control types. It's believed that there is a server bug
// which can allow this to happen (crbug.com/164288). The sync engine should
// detect this condition and fail to initialize the backend.
//
// The failure is "silent" in the sense that the GetUpdates request appears to
// be successful, but it returned no results. This means that the usual
// download retry logic will not be invoked.
TEST_F(SyncEngineImplTest, SilentlyFailToDownloadControlTypes) {
fake_manager_factory_->set_configure_fail_types(DataTypeSet::All());
InitializeBackend(/*expect_success=*/false);
}
// Test that local refresh requests are delivered to sync.
TEST_F(SyncEngineImplTest, ForwardLocalRefreshRequest) {
InitializeBackend();
const DataTypeSet set1 = DataTypeSet::All();
backend_->TriggerRefresh(set1);
fake_manager_->WaitForSyncThread();
EXPECT_EQ(set1, fake_manager_->GetLastRefreshRequestTypes());
const DataTypeSet set2 = {SESSIONS};
backend_->TriggerRefresh(set2);
fake_manager_->WaitForSyncThread();
EXPECT_EQ(set2, fake_manager_->GetLastRefreshRequestTypes());
}
// Test that configuration on signin sends the proper GU source.
TEST_F(SyncEngineImplTest, DownloadControlTypesNewClient) {
InitializeBackend();
EXPECT_EQ(CONFIGURE_REASON_NEW_CLIENT,
fake_manager_->GetAndResetConfigureReason());
}
// Test that configuration on restart sends the proper GU source.
TEST_F(SyncEngineImplTest, DownloadControlTypesRestart) {
fake_manager_factory_->set_progress_marker_types(enabled_types_);
fake_manager_factory_->set_initial_sync_ended_types(enabled_types_);
InitializeBackend();
EXPECT_EQ(CONFIGURE_REASON_EXISTING_CLIENT_RESTART,
fake_manager_->GetAndResetConfigureReason());
}
// Tests that SyncEngineImpl retains DataTypeConnector after call to
// StopSyncingForShutdown. This is needed for datatype deactivation during
// DataTypeManager shutdown.
TEST_F(SyncEngineImplTest, DataTypeConnectorValidDuringShutdown) {
InitializeBackend();
backend_->StopSyncingForShutdown();
// Verify that call to DisconnectDataType doesn't assert.
backend_->DisconnectDataType(AUTOFILL);
// Reset `fake_manager_` to avoid dangling pointer.
fake_manager_ = nullptr;
backend_->Shutdown(ShutdownReason::STOP_SYNC_AND_KEEP_DATA);
backend_.reset();
}
TEST_F(SyncEngineImplTest, ShouldInvalidateDataTypesOnIncomingInvalidation) {
enabled_types_.PutAll({syncer::BOOKMARKS, syncer::PREFERENCES});
InitializeBackend(/*expect_success=*/true);
ConfigureDataTypes();
sync_pb::SyncInvalidationsPayload payload;
sync_pb::SyncInvalidationsPayload::DataTypeInvalidation*
bookmarks_invalidation = payload.add_data_type_invalidations();
bookmarks_invalidation->set_data_type_id(
GetSpecificsFieldNumberFromDataType(DataType::BOOKMARKS));
sync_pb::SyncInvalidationsPayload::DataTypeInvalidation*
preferences_invalidation = payload.add_data_type_invalidations();
preferences_invalidation->set_data_type_id(
GetSpecificsFieldNumberFromDataType(DataType::PREFERENCES));
EXPECT_CALL(mock_sync_invalidations_service_, GetInterestedDataTypes())
.WillOnce(Return(enabled_types_));
backend_->OnInvalidationReceived(payload.SerializeAsString());
fake_manager_->WaitForSyncThread();
EXPECT_EQ(1, fake_manager_->GetInvalidationCount(DataType::BOOKMARKS));
EXPECT_EQ(1, fake_manager_->GetInvalidationCount(DataType::PREFERENCES));
}
TEST_F(SyncEngineImplTest, ShouldInvalidateOnlyEnabledDataTypes) {
enabled_types_.Remove(syncer::BOOKMARKS);
enabled_types_.Put(syncer::PREFERENCES);
InitializeBackend(/*expect_success=*/true);
ConfigureDataTypes();
sync_pb::SyncInvalidationsPayload payload;
sync_pb::SyncInvalidationsPayload::DataTypeInvalidation*
bookmarks_invalidation = payload.add_data_type_invalidations();
bookmarks_invalidation->set_data_type_id(
GetSpecificsFieldNumberFromDataType(DataType::BOOKMARKS));
sync_pb::SyncInvalidationsPayload::DataTypeInvalidation*
preferences_invalidation = payload.add_data_type_invalidations();
preferences_invalidation->set_data_type_id(
GetSpecificsFieldNumberFromDataType(DataType::PREFERENCES));
EXPECT_CALL(mock_sync_invalidations_service_, GetInterestedDataTypes())
.WillOnce(Return(enabled_types_));
backend_->OnInvalidationReceived(payload.SerializeAsString());
fake_manager_->WaitForSyncThread();
EXPECT_EQ(0, fake_manager_->GetInvalidationCount(DataType::BOOKMARKS));
EXPECT_EQ(1, fake_manager_->GetInvalidationCount(DataType::PREFERENCES));
}
TEST_F(SyncEngineImplTest, ShouldStartHandlingInvalidations) {
InitializeBackend(/*expect_success=*/true);
EXPECT_CALL(mock_sync_invalidations_service_, AddListener(backend_.get()));
backend_->StartHandlingInvalidations();
}
TEST_F(SyncEngineImplTest, DoNotUseOldInvalidationsAtAll) {
enabled_types_.PutAll({AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER});
EXPECT_CALL(mock_sync_invalidations_service_, GetInterestedDataTypes())
.WillRepeatedly(Return(enabled_types_));
InitializeBackend(/*expect_success=*/true);
ConfigureDataTypes();
}
TEST_F(SyncEngineImplTest, ShouldEnableInvalidationsWhenStartedHandling) {
EXPECT_CALL(mock_sync_invalidations_service_, HasListener)
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_sync_invalidations_service_, GetFCMRegistrationToken)
.WillRepeatedly(Return("fcm_token"));
InitializeBackend(/*expect_success=*/true);
backend_->StartHandlingInvalidations();
fake_manager_->WaitForSyncThread();
EXPECT_TRUE(fake_manager_->IsInvalidatorEnabled());
}
TEST_F(SyncEngineImplTest, ShouldEnableInvalidationsOnTokenUpdate) {
EXPECT_CALL(mock_sync_invalidations_service_, GetFCMRegistrationToken)
.WillRepeatedly(Return(std::nullopt));
InitializeBackend(/*expect_success=*/true);
fake_manager_->WaitForSyncThread();
// Simulate listening for invalidations but since an FCM token hasn't been
// obtained, the invalidator is still disabled.
ON_CALL(mock_sync_invalidations_service_, HasListener)
.WillByDefault(Return(true));
EXPECT_FALSE(fake_manager_->IsInvalidatorEnabled());
EXPECT_CALL(mock_sync_invalidations_service_, GetFCMRegistrationToken)
.WillRepeatedly(Return("fcm_token"));
backend_->OnFCMRegistrationTokenChanged();
fake_manager_->WaitForSyncThread();
EXPECT_TRUE(fake_manager_->IsInvalidatorEnabled());
}
TEST_F(SyncEngineImplTest, GenerateCacheGUID) {
const std::string guid1 = SyncEngineImpl::GenerateCacheGUIDForTest();
const std::string guid2 = SyncEngineImpl::GenerateCacheGUIDForTest();
EXPECT_EQ(24U, guid1.size());
EXPECT_EQ(24U, guid2.size());
EXPECT_NE(guid1, guid2);
}
TEST_F(SyncEngineImplTest, ShouldLoadSyncDataUponInitialization) {
SyncTransportDataPrefs transport_data_prefs(
&pref_service_, signin::GaiaIdHash::FromGaiaId(kTestGaiaId));
transport_data_prefs.SetCacheGuid(kTestCacheGuid);
transport_data_prefs.SetBirthday(kTestBirthday);
transport_data_prefs.SetCurrentSyncingGaiaId(kTestGaiaId);
InitializeBackend();
EXPECT_EQ(kTestGaiaId, transport_data_prefs.GetCurrentSyncingGaiaId());
EXPECT_EQ(kTestCacheGuid, transport_data_prefs.GetCacheGuid());
EXPECT_EQ(kTestBirthday, transport_data_prefs.GetBirthday());
}
TEST_F(SyncEngineImplTest, ShouldNotifyOnNewInvalidatedDataTypes) {
InitializeBackend();
ConfigureDataTypes();
// Use OnInvalidationStatusChanged() to verify that
// OnNewInvalidatedDataTypes() is caled only once in the beginning, and all
// the next invalidated data types updates should not notify.
Sequence seq;
EXPECT_CALL(mock_host_, OnNewInvalidatedDataTypes).InSequence(seq);
EXPECT_CALL(mock_host_, OnInvalidationStatusChanged).InSequence(seq);
SyncStatus sync_status;
sync_status.invalidated_data_types.Put(BOOKMARKS);
fake_manager_->NotifySyncStatusChanged(sync_status);
fake_manager_->WaitForSyncThread();
// Turn on notifications to trigger OnInvalidationStatusChanged().
sync_status.notifications_enabled = true;
fake_manager_->NotifySyncStatusChanged(sync_status);
fake_manager_->WaitForSyncThread();
// Removing an invalidated data type shouldn't invoke
// OnNewInvalidatedDataTypes().
sync_status.invalidated_data_types.Remove(BOOKMARKS);
fake_manager_->NotifySyncStatusChanged(sync_status);
fake_manager_->WaitForSyncThread();
}
TEST_F(SyncEngineImplTest, ShouldReturnWhetherNextPollTimePassed) {
SyncTransportDataPrefs transport_data_prefs(
&pref_service_, signin::GaiaIdHash::FromGaiaId(kTestGaiaId));
transport_data_prefs.SetCacheGuid(kTestCacheGuid);
transport_data_prefs.SetBirthday(kTestBirthday);
transport_data_prefs.SetCurrentSyncingGaiaId(kTestGaiaId);
transport_data_prefs.SetLastPollTime(base::Time::Now() - base::Hours(5));
transport_data_prefs.SetPollInterval(base::Hours(4));
InitializeBackend();
ConfigureDataTypes();
EXPECT_TRUE(backend_->IsNextPollTimeInThePast());
// Mimic a finished PERIODIC sync cycle.
SyncCycleSnapshot snapshot(
/*birthday=*/std::string(),
/*bag_of_chips=*/std::string(), ModelNeutralState(), ProgressMarkerMap(),
/*is_silenced=*/false,
/*num_server_conflicts=*/0,
/*notifications_enabled=*/true,
/*sync_start_time=*/base::Time::Now(),
/*poll_finish_time=*/base::Time::Now(),
/*get_updates_origin=*/sync_pb::SyncEnums::PERIODIC,
/*poll_interval=*/base::Hours(4),
/*has_remaining_local_changes=*/false);
fake_manager_->NotifySyncCycleCompleted(snapshot);
fake_manager_->WaitForSyncThread();
EXPECT_FALSE(backend_->IsNextPollTimeInThePast());
}
} // namespace
} // namespace syncer