blob: 5c45ae417fb12dc56c5e7cba0fc554c1d339045f [file] [log] [blame]
// Copyright 2018 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 "components/sync/driver/sync_service_utils.h"
#include <vector>
#include "components/sync/base/model_type.h"
#include "components/sync/driver/fake_sync_service.h"
#include "components/sync/driver/sync_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
class TestSyncService : public FakeSyncService {
public:
TestSyncService() = default;
~TestSyncService() override = default;
void SetDisableReasons(int disable_reasons) {
disable_reasons_ = disable_reasons;
}
void SetTransportState(TransportState state) { state_ = state; }
void SetLocalSyncEnabled(bool local) { local_sync_enabled_ = local; }
void SetPreferredDataTypes(const ModelTypeSet& types) {
preferred_data_types_ = types;
}
void SetActiveDataTypes(const ModelTypeSet& types) {
active_data_types_ = types;
}
void SetCustomPassphraseEnabled(bool enabled) {
custom_passphrase_enabled_ = enabled;
}
void SetSyncCycleComplete(bool complete) { sync_cycle_complete_ = complete; }
// SyncService implementation.
int GetDisableReasons() const override { return disable_reasons_; }
TransportState GetTransportState() const override { return state_; }
bool IsLocalSyncEnabled() const override { return local_sync_enabled_; }
bool IsFirstSetupComplete() const override { return true; }
ModelTypeSet GetPreferredDataTypes() const override {
return preferred_data_types_;
}
ModelTypeSet GetActiveDataTypes() const override {
if (!IsSyncActive())
return ModelTypeSet();
return active_data_types_;
}
ModelTypeSet GetEncryptedDataTypes() const override {
if (!custom_passphrase_enabled_) {
// PASSWORDS are always encrypted.
return ModelTypeSet(syncer::PASSWORDS);
}
// Some types can never be encrypted, e.g. DEVICE_INFO and
// AUTOFILL_WALLET_DATA, so make sure we don't report them as encrypted.
return syncer::Intersection(preferred_data_types_,
syncer::EncryptableUserTypes());
}
SyncCycleSnapshot GetLastCycleSnapshot() const override {
if (sync_cycle_complete_) {
return SyncCycleSnapshot(
ModelNeutralState(), ProgressMarkerMap(), false, 5, 2, 7, false, 0,
base::Time::Now(), base::Time::Now(),
std::vector<int>(MODEL_TYPE_COUNT, 0),
std::vector<int>(MODEL_TYPE_COUNT, 0),
sync_pb::SyncEnums::UNKNOWN_ORIGIN,
/*short_poll_interval=*/base::TimeDelta::FromMinutes(30),
/*long_poll_interval=*/base::TimeDelta::FromMinutes(180),
/*has_remaining_local_changes=*/false);
}
return SyncCycleSnapshot();
}
bool IsUsingSecondaryPassphrase() const override {
return custom_passphrase_enabled_;
}
private:
int disable_reasons_ = DISABLE_REASON_PLATFORM_OVERRIDE;
TransportState state_ = TransportState::DISABLED;
bool sync_cycle_complete_ = false;
bool local_sync_enabled_ = false;
ModelTypeSet preferred_data_types_;
ModelTypeSet active_data_types_;
bool custom_passphrase_enabled_ = false;
};
TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfSyncNotAllowed) {
TestSyncService service;
// If sync is not allowed, uploading should never be enabled, even if all the
// data types are enabled.
service.SetDisableReasons(
syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
service.SetPreferredDataTypes(ProtocolTypes());
service.SetActiveDataTypes(ProtocolTypes());
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// Once sync gets allowed (e.g. policy is updated), uploading should not be
// disabled anymore (though not necessarily active yet).
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetTransportState(
syncer::SyncService::TransportState::WAITING_FOR_START_REQUEST);
EXPECT_NE(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
}
TEST(SyncServiceUtilsTest,
UploadToGoogleInitializingUntilConfiguredAndActiveAndSyncCycleComplete) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetTransportState(
syncer::SyncService::TransportState::WAITING_FOR_START_REQUEST);
service.SetPreferredDataTypes(ProtocolTypes());
service.SetActiveDataTypes(ProtocolTypes());
// By default, if sync isn't disabled, we should be INITIALIZING.
EXPECT_EQ(UploadState::INITIALIZING,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// Finished configuration is not enough, still INITIALIZING.
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
EXPECT_EQ(UploadState::INITIALIZING,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// Only after a sync cycle has been completed is upload actually ACTIVE.
service.SetSyncCycleComplete(true);
EXPECT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
}
TEST(SyncServiceUtilsTest, UploadToGoogleDisabledForModelType) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
service.SetSyncCycleComplete(true);
// Sync is enabled only for a specific model type.
service.SetPreferredDataTypes(ModelTypeSet(syncer::BOOKMARKS));
service.SetActiveDataTypes(ModelTypeSet(syncer::BOOKMARKS));
// Sanity check: Upload is ACTIVE for this model type.
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// ...but not for other types.
EXPECT_EQ(
UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::HISTORY_DELETE_DIRECTIVES));
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::PREFERENCES));
}
TEST(SyncServiceUtilsTest,
UploadToGoogleDisabledForModelTypeThatFailedToStart) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
service.SetSyncCycleComplete(true);
// Sync is enabled for some model types.
service.SetPreferredDataTypes(
ModelTypeSet(syncer::BOOKMARKS, syncer::PREFERENCES));
// But one of them fails to actually start up!
service.SetActiveDataTypes(ModelTypeSet(syncer::BOOKMARKS));
// Sanity check: Upload is ACTIVE for the model type that did start up.
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// ...but not for the type that failed.
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::PREFERENCES));
}
TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfLocalSyncEnabled) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetPreferredDataTypes(ProtocolTypes());
service.SetActiveDataTypes(ProtocolTypes());
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
service.SetSyncCycleComplete(true);
// Sanity check: Upload is active now.
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// If we're in "local sync" mode, uploading should never be enabled, even if
// configuration is done and all the data types are enabled.
service.SetLocalSyncEnabled(true);
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
}
TEST(SyncServiceUtilsTest, UploadToGoogleDisabledOnPersistentAuthError) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetPreferredDataTypes(ProtocolTypes());
service.SetActiveDataTypes(ProtocolTypes());
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
service.SetSyncCycleComplete(true);
// Sanity check: Upload is active now.
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// On a transient error, uploading goes back to INITIALIZING.
GoogleServiceAuthError transient_error(
GoogleServiceAuthError::CONNECTION_FAILED);
ASSERT_TRUE(transient_error.IsTransientError());
service.set_auth_error(transient_error);
EXPECT_EQ(UploadState::INITIALIZING,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// On a persistent error, uploading is not considered active anymore (even
// though Sync may still be considered active).
GoogleServiceAuthError persistent_error(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
ASSERT_TRUE(persistent_error.IsPersistentError());
service.set_auth_error(persistent_error);
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
// Once the auth error is resolved (e.g. user re-authenticated), uploading is
// active again.
service.set_auth_error(GoogleServiceAuthError(GoogleServiceAuthError::NONE));
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
EXPECT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
}
TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfCustomPassphraseInUse) {
TestSyncService service;
service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
service.SetPreferredDataTypes(ProtocolTypes());
service.SetActiveDataTypes(ProtocolTypes());
service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
service.SetSyncCycleComplete(true);
// Sanity check: Upload is ACTIVE, even for data types that are always
// encrypted implicitly (PASSWORDS).
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::PASSWORDS));
ASSERT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::DEVICE_INFO));
// Once a custom passphrase is in use, upload should be considered disabled:
// Even if we're technically still uploading, Google can't inspect the data.
service.SetCustomPassphraseEnabled(true);
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::BOOKMARKS));
EXPECT_EQ(UploadState::NOT_ACTIVE,
GetUploadToGoogleState(&service, syncer::PASSWORDS));
// But unencryptable types like DEVICE_INFO are still active.
EXPECT_EQ(UploadState::ACTIVE,
GetUploadToGoogleState(&service, syncer::DEVICE_INFO));
}
} // namespace syncer