blob: 3f63fc49247d0abe40c8100e9a07a71d5ba6b039 [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 "components/browser_sync/profile_sync_service.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/browser_sync/profile_sync_test_util.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/common/signin_pref_names.h"
#include "components/sync/base/pref_names.h"
#include "components/sync/driver/data_type_manager_mock.h"
#include "components/sync/driver/fake_data_type_controller.h"
#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "components/sync/driver/sync_service_observer.h"
#include "components/sync/engine/fake_sync_engine.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_constants.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using syncer::DataTypeManager;
using syncer::DataTypeManagerMock;
using syncer::FakeSyncEngine;
using testing::_;
using testing::AnyNumber;
using testing::DoAll;
using testing::Mock;
using testing::Return;
namespace browser_sync {
namespace {
const char kGaiaId[] = "12345";
const char kEmail[] = "test_user@gmail.com";
const char kDummyPassword[] = "foobar";
class SyncServiceObserverMock : public syncer::SyncServiceObserver {
public:
SyncServiceObserverMock();
virtual ~SyncServiceObserverMock();
MOCK_METHOD1(OnStateChanged, void(syncer::SyncService*));
};
SyncServiceObserverMock::SyncServiceObserverMock() {}
SyncServiceObserverMock::~SyncServiceObserverMock() {}
} // namespace
ACTION_P(InvokeOnConfigureStart, sync_service) {
sync_service->OnConfigureStart();
}
ACTION_P3(InvokeOnConfigureDone, sync_service, error_callback, result) {
DataTypeManager::ConfigureResult configure_result =
static_cast<DataTypeManager::ConfigureResult>(result);
if (result.status == syncer::DataTypeManager::ABORTED)
error_callback.Run(&configure_result);
sync_service->OnConfigureDone(configure_result);
}
class ProfileSyncServiceStartupTest : public testing::Test {
public:
ProfileSyncServiceStartupTest() {
profile_sync_service_bundle_.auth_service()
->set_auto_post_fetch_response_on_message_loop(true);
}
~ProfileSyncServiceStartupTest() override {
sync_service_->RemoveObserver(&observer_);
sync_service_->Shutdown();
}
void CreateSyncService(ProfileSyncService::StartBehavior start_behavior) {
component_factory_ = profile_sync_service_bundle_.component_factory();
ProfileSyncServiceBundle::SyncClientBuilder builder(
&profile_sync_service_bundle_);
ProfileSyncService::InitParams init_params =
profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
builder.Build());
sync_service_ =
base::MakeUnique<ProfileSyncService>(std::move(init_params));
sync_service_->RegisterDataTypeController(
base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
sync_service_->AddObserver(&observer_);
}
void IssueTestTokens(const std::string& account_id) {
profile_sync_service_bundle_.auth_service()->UpdateCredentials(
account_id, "oauth2_login_token");
}
void SetError(DataTypeManager::ConfigureResult* result) {
syncer::DataTypeStatusTable::TypeErrorMap errors;
errors[syncer::BOOKMARKS] =
syncer::SyncError(FROM_HERE, syncer::SyncError::UNRECOVERABLE_ERROR,
"Error", syncer::BOOKMARKS);
result->data_type_status_table.UpdateFailedDataTypes(errors);
}
protected:
std::string SimulateTestUserSignin(ProfileSyncService* sync_service) {
std::string account_id =
profile_sync_service_bundle_.account_tracker()->SeedAccountInfo(kGaiaId,
kEmail);
pref_service()->SetString(prefs::kGoogleServicesAccountId, account_id);
#if !defined(OS_CHROMEOS)
profile_sync_service_bundle_.signin_manager()->SignIn(kGaiaId, kEmail,
kDummyPassword);
#else
profile_sync_service_bundle_.signin_manager()->SetAuthenticatedAccountInfo(
kGaiaId, kEmail);
if (sync_service)
sync_service->GoogleSigninSucceeded(account_id, kEmail, kDummyPassword);
#endif
return account_id;
}
DataTypeManagerMock* SetUpDataTypeManager() {
DataTypeManagerMock* data_type_manager = new DataTypeManagerMock();
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
.WillOnce(Return(data_type_manager));
return data_type_manager;
}
FakeSyncEngine* SetUpSyncEngine() {
FakeSyncEngine* sync_backend_host = new FakeSyncEngine();
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
.WillOnce(Return(sync_backend_host));
return sync_backend_host;
}
PrefService* pref_service() {
return profile_sync_service_bundle_.pref_service();
}
base::MessageLoop message_loop_;
ProfileSyncServiceBundle profile_sync_service_bundle_;
std::unique_ptr<ProfileSyncService> sync_service_;
SyncServiceObserverMock observer_;
syncer::DataTypeStatusTable data_type_status_table_;
syncer::SyncApiComponentFactoryMock* component_factory_ = nullptr;
};
class ProfileSyncServiceStartupCrosTest : public ProfileSyncServiceStartupTest {
public:
ProfileSyncServiceStartupCrosTest() {
CreateSyncService(ProfileSyncService::AUTO_START);
SimulateTestUserSignin(nullptr);
EXPECT_TRUE(
profile_sync_service_bundle_.signin_manager()->IsAuthenticated());
}
};
TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
// We've never completed startup.
pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
CreateSyncService(ProfileSyncService::MANUAL_START);
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
// Should not actually start, rather just clean things up and wait
// to be enabled.
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
// Preferences should be back to defaults.
EXPECT_EQ(0, pref_service()->GetInt64(syncer::prefs::kSyncLastSyncedTime));
EXPECT_FALSE(
pref_service()->GetBoolean(syncer::prefs::kSyncFirstSetupComplete));
Mock::VerifyAndClearExpectations(data_type_manager);
// Then start things up.
EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(1);
EXPECT_CALL(*data_type_manager, state())
.WillOnce(Return(DataTypeManager::CONFIGURED))
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
auto sync_blocker = sync_service_->GetSetupInProgressHandle();
// Simulate successful signin as test_user.
std::string account_id = SimulateTestUserSignin(sync_service_.get());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
// Create some tokens in the token service.
IssueTestTokens(account_id);
// Simulate the UI telling sync it has finished setting up.
sync_blocker.reset();
sync_service_->SetFirstSetupComplete();
EXPECT_TRUE(sync_service_->IsSyncActive());
}
// TODO(pavely): Reenable test once android is switched to oauth2.
TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartNoCredentials) {
// We've never completed startup.
pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
CreateSyncService(ProfileSyncService::MANUAL_START);
// Should not actually start, rather just clean things up and wait
// to be enabled.
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
.Times(0);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
// Preferences should be back to defaults.
EXPECT_EQ(0, pref_service()->GetInt64(syncer::prefs::kSyncLastSyncedTime));
EXPECT_FALSE(
pref_service()->GetBoolean(syncer::prefs::kSyncFirstSetupComplete));
// Then start things up.
auto sync_blocker = sync_service_->GetSetupInProgressHandle();
// Simulate successful signin as test_user.
std::string account_id = SimulateTestUserSignin(sync_service_.get());
profile_sync_service_bundle_.auth_service()->LoadCredentials(account_id);
sync_blocker.reset();
// ProfileSyncService should try to start by requesting access token.
// This request should fail as login token was not issued.
EXPECT_FALSE(sync_service_->IsSyncActive());
EXPECT_EQ(GoogleServiceAuthError::USER_NOT_SIGNED_UP,
sync_service_->GetAuthError().state());
}
// TODO(pavely): Reenable test once android is switched to oauth2.
TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartInvalidCredentials) {
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
FakeSyncEngine* mock_sbh = SetUpSyncEngine();
// Tell the backend to stall while downloading control types (simulating an
// auth error).
mock_sbh->set_fail_initial_download(true);
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
EXPECT_FALSE(sync_service_->IsSyncActive());
Mock::VerifyAndClearExpectations(data_type_manager);
// Update the credentials, unstalling the backend.
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
auto sync_blocker = sync_service_->GetSetupInProgressHandle();
// Simulate successful signin.
SimulateTestUserSignin(sync_service_.get());
sync_blocker.reset();
// Verify we successfully finish startup and configuration.
EXPECT_TRUE(sync_service_->IsSyncActive());
}
TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _)).Times(0);
pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
// Sync should not start because there are no tokens yet.
EXPECT_FALSE(sync_service_->IsSyncActive());
sync_service_->SetFirstSetupComplete();
// Sync should not start because there are still no tokens.
EXPECT_FALSE(sync_service_->IsSyncActive());
}
TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop());
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
IssueTestTokens(
profile_sync_service_bundle_.account_tracker()->PickAccountIdForAccount(
"12345", kEmail));
sync_service_->Initialize();
EXPECT_TRUE(sync_service_->IsSyncActive());
}
TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
// Pre load the tokens
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
sync_service_->SetFirstSetupComplete();
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
IssueTestTokens(account_id);
sync_service_->Initialize();
}
// Test that we can recover from a case where a bug in the code resulted in
// OnUserChoseDatatypes not being properly called and datatype preferences
// therefore being left unset.
TEST_F(ProfileSyncServiceStartupTest, StartRecoverDatatypePrefs) {
// Clear the datatype preference fields (simulating bug 154940).
pref_service()->ClearPref(syncer::prefs::kSyncKeepEverythingSynced);
syncer::ModelTypeSet user_types = syncer::UserTypes();
for (syncer::ModelTypeSet::Iterator iter = user_types.First(); iter.Good();
iter.Inc()) {
pref_service()->ClearPref(
syncer::SyncPrefs::GetPrefNameForDataType(iter.Get()));
}
// Pre load the tokens
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
sync_service_->SetFirstSetupComplete();
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
IssueTestTokens(account_id);
sync_service_->Initialize();
EXPECT_TRUE(
pref_service()->GetBoolean(syncer::prefs::kSyncKeepEverythingSynced));
}
// Verify that the recovery of datatype preferences doesn't overwrite a valid
// case where only bookmarks are enabled.
TEST_F(ProfileSyncServiceStartupTest, StartDontRecoverDatatypePrefs) {
// Explicitly set Keep Everything Synced to false and have only bookmarks
// enabled.
pref_service()->SetBoolean(syncer::prefs::kSyncKeepEverythingSynced, false);
// Pre load the tokens
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
sync_service_->SetFirstSetupComplete();
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
IssueTestTokens(account_id);
sync_service_->Initialize();
EXPECT_FALSE(
pref_service()->GetBoolean(syncer::prefs::kSyncKeepEverythingSynced));
}
TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
// Service should not be started by Initialize() since it's managed.
pref_service()->SetString(prefs::kGoogleServicesAccountId, kEmail);
CreateSyncService(ProfileSyncService::MANUAL_START);
// Disable sync through policy.
pref_service()->SetBoolean(syncer::prefs::kSyncManaged, true);
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
.Times(0);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
}
TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
sync_service_->SetFirstSetupComplete();
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(*data_type_manager, state())
.WillRepeatedly(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
IssueTestTokens(account_id);
sync_service_->Initialize();
EXPECT_TRUE(sync_service_->IsEngineInitialized());
EXPECT_TRUE(sync_service_->IsSyncActive());
// The service should stop when switching to managed mode.
Mock::VerifyAndClearExpectations(data_type_manager);
EXPECT_CALL(*data_type_manager, state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
pref_service()->SetBoolean(syncer::prefs::kSyncManaged, true);
EXPECT_FALSE(sync_service_->IsEngineInitialized());
// Note that PSS no longer references |data_type_manager| after stopping.
// When switching back to unmanaged, the state should change but sync should
// not start automatically because IsFirstSetupComplete() will be false.
// A new DataTypeManager should not be created.
Mock::VerifyAndClearExpectations(data_type_manager);
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
.Times(0);
pref_service()->ClearPref(syncer::prefs::kSyncManaged);
EXPECT_FALSE(sync_service_->IsEngineInitialized());
EXPECT_FALSE(sync_service_->IsSyncActive());
}
TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
sync_service_->SetFirstSetupComplete();
SetUpSyncEngine();
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
DataTypeManager::ConfigureResult result(status, syncer::ModelTypeSet());
EXPECT_CALL(*data_type_manager, Configure(_, _))
.WillRepeatedly(
DoAll(InvokeOnConfigureStart(sync_service_.get()),
InvokeOnConfigureDone(
sync_service_.get(),
base::Bind(&ProfileSyncServiceStartupTest::SetError,
base::Unretained(this)),
result)));
EXPECT_CALL(*data_type_manager, state())
.WillOnce(Return(DataTypeManager::STOPPED));
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
ON_CALL(*data_type_manager, IsNigoriEnabled()).WillByDefault(Return(true));
IssueTestTokens(account_id);
sync_service_->Initialize();
EXPECT_TRUE(sync_service_->HasUnrecoverableError());
}
TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
// Pre load the tokens
CreateSyncService(ProfileSyncService::MANUAL_START);
std::string account_id = SimulateTestUserSignin(sync_service_.get());
FakeSyncEngine* mock_sbh = SetUpSyncEngine();
mock_sbh->set_fail_initial_download(true);
pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
EXPECT_CALL(observer_, OnStateChanged(_)).Times(AnyNumber());
sync_service_->Initialize();
auto sync_blocker = sync_service_->GetSetupInProgressHandle();
IssueTestTokens(account_id);
sync_blocker.reset();
EXPECT_FALSE(sync_service_->IsSyncActive());
}
} // namespace browser_sync