blob: d4f2b07a23d3ca82c87fe0c4e61b5ee3bef641fe [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 "testing/gtest/include/gtest/gtest.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_manager_fake.h"
#include "chrome/browser/signin/token_service.h"
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/browser/sync/glue/data_type_manager.h"
#include "chrome/browser/sync/glue/data_type_manager_mock.h"
#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
using browser_sync::DataTypeManager;
using browser_sync::DataTypeManagerMock;
using content::BrowserThread;
using testing::_;
using testing::AnyNumber;
using testing::DoAll;
using testing::InvokeArgument;
using testing::Mock;
using testing::Return;
ACTION_P(InvokeOnConfigureStart, pss) {
TestProfileSyncService* service = static_cast<TestProfileSyncService*>(pss);
service->OnConfigureStart();
}
ACTION_P2(InvokeOnConfigureDone, pss, result) {
TestProfileSyncService* service = static_cast<TestProfileSyncService*>(pss);
DataTypeManager::ConfigureResult configure_result =
static_cast<DataTypeManager::ConfigureResult>(result);
service->OnConfigureDone(configure_result);
}
// TODO(chron): Test not using cros_user flag and use signin_
class ProfileSyncServiceStartupTest : public testing::Test {
public:
ProfileSyncServiceStartupTest()
: ui_thread_(BrowserThread::UI, &ui_loop_),
db_thread_(BrowserThread::DB),
file_thread_(BrowserThread::FILE),
io_thread_(BrowserThread::IO),
profile_(new TestingProfile) {}
virtual ~ProfileSyncServiceStartupTest() {
}
virtual void SetUp() {
file_thread_.Start();
io_thread_.StartIOThread();
profile_->CreateRequestContext();
CreateSyncService();
service_->AddObserver(&observer_);
service_->set_synchronous_sync_configuration();
}
virtual void TearDown() {
service_->RemoveObserver(&observer_);
service_.reset();
profile_.reset();
// Pump messages posted by the sync core thread (which may end up
// posting on the IO thread).
ui_loop_.RunAllPending();
io_thread_.Stop();
file_thread_.Stop();
ui_loop_.RunAllPending();
}
protected:
// Overridden below by ProfileSyncServiceStartupCrosTest.
virtual void CreateSyncService() {
SigninManager* signin = static_cast<SigninManager*>(
SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
profile_.get(), FakeSigninManager::Build));
signin->SetAuthenticatedUsername("test_user");
service_.reset(new TestProfileSyncService(
new ProfileSyncComponentsFactoryMock(),
profile_.get(),
signin,
ProfileSyncService::MANUAL_START,
true,
base::Closure()));
}
DataTypeManagerMock* SetUpDataTypeManager() {
DataTypeManagerMock* data_type_manager = new DataTypeManagerMock();
EXPECT_CALL(*factory_mock(), CreateDataTypeManager(_, _, _)).
WillOnce(Return(data_type_manager));
return data_type_manager;
}
ProfileSyncComponentsFactoryMock* factory_mock() {
return static_cast<ProfileSyncComponentsFactoryMock*>(service_->factory());
}
MessageLoop ui_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread db_thread_;
content::TestBrowserThread file_thread_;
content::TestBrowserThread io_thread_;
scoped_ptr<TestingProfile> profile_;
scoped_ptr<TestProfileSyncService> service_;
ProfileSyncServiceObserverMock observer_;
};
class ProfileSyncServiceStartupCrosTest : public ProfileSyncServiceStartupTest {
protected:
virtual void CreateSyncService() {
SigninManager* signin = SigninManagerFactory::GetForProfile(profile_.get());
signin->SetAuthenticatedUsername("test_user");
service_.reset(new TestProfileSyncService(
new ProfileSyncComponentsFactoryMock(),
profile_.get(),
signin,
ProfileSyncService::AUTO_START,
true,
base::Closure()));
}
};
TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
// We've never completed startup.
profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
// Make sure SigninManager doesn't think we're signed in (undoes the call to
// SetAuthenticatedUsername() in CreateSyncService()).
SigninManagerFactory::GetForProfile(profile_.get())->SignOut();
// Should not actually start, rather just clean things up and wait
// to be enabled.
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
service_->Initialize();
// Preferences should be back to defaults.
EXPECT_EQ(0, profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted));
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());
// Create some tokens in the token service; the service will startup when
// it is notified that tokens are available.
service_->SetSetupInProgress(true);
service_->signin()->StartSignIn("test_user", "", "", "");
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth2_login_token");
service_->SetSetupInProgress(false);
EXPECT_TRUE(service_->ShouldPushChanges());
}
TEST_F(ProfileSyncServiceStartupTest, StartNoCredentials) {
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
// We've never completed startup.
profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
// Make sure SigninManager doesn't think we're signed in (undoes the call to
// SetAuthenticatedUsername() in CreateSyncService()).
SigninManagerFactory::GetForProfile(profile_.get())->SignOut();
// Should not actually start, rather just clean things up and wait
// to be enabled.
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
service_->Initialize();
EXPECT_FALSE(service_->GetBackendForTest());
// Preferences should be back to defaults.
EXPECT_EQ(0, profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted));
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());
service_->SetSetupInProgress(true);
service_->signin()->StartSignIn("test_user", "", "", "");
// NOTE: Unlike StartFirstTime, this test does not issue any auth tokens.
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
content::Source<TokenService>(
TokenServiceFactory::GetForProfile(profile_.get())),
content::NotificationService::NoDetails());
service_->SetSetupInProgress(false);
// Backend should initialize using a bogus GAIA token for credentials.
EXPECT_TRUE(service_->ShouldPushChanges());
}
TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
EXPECT_CALL(*factory_mock(), CreateDataTypeManager(_, _, _)).Times(0);
profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
service_->Initialize();
// Sync should not start because there are no tokens yet.
EXPECT_FALSE(service_->ShouldPushChanges());
EXPECT_FALSE(service_->GetBackendForTest());
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
content::Source<TokenService>(
TokenServiceFactory::GetForProfile(profile_.get())),
content::NotificationService::NoDetails());
service_->SetSetupInProgress(false);
// Sync should not start because there are still no tokens.
EXPECT_FALSE(service_->ShouldPushChanges());
EXPECT_FALSE(service_->GetBackendForTest());
}
TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
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());
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
EXPECT_TRUE(service_->ShouldPushChanges());
}
TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
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());
// Pre load the tokens
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
service_->Initialize();
}
TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
// Disable sync through policy.
profile_->GetPrefs()->SetBoolean(prefs::kSyncManaged, true);
EXPECT_CALL(*factory_mock(), CreateDataTypeManager(_, _, _)).Times(0);
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
// Service should not be started by Initialize() since it's managed.
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
service_->Initialize();
}
TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
EXPECT_CALL(*data_type_manager, Configure(_, _));
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
service_->Initialize();
// 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);
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
profile_->GetPrefs()->SetBoolean(prefs::kSyncManaged, true);
// When switching back to unmanaged, the state should change, but the service
// should not start up automatically (kSyncSetupCompleted will be false).
Mock::VerifyAndClearExpectations(data_type_manager);
EXPECT_CALL(*factory_mock(), CreateDataTypeManager(_, _, _)).Times(0);
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
profile_->GetPrefs()->ClearPref(prefs::kSyncManaged);
}
TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
syncer::SyncError error(
FROM_HERE, "Association failed.", syncer::BOOKMARKS);
std::list<syncer::SyncError> errors;
errors.push_back(error);
DataTypeManager::ConfigureResult result(
status,
syncer::ModelTypeSet(),
errors,
syncer::ModelTypeSet());
EXPECT_CALL(*data_type_manager, Configure(_, _)).
WillRepeatedly(
DoAll(InvokeOnConfigureStart(service_.get()),
InvokeOnConfigureDone(service_.get(), result)));
EXPECT_CALL(*data_type_manager, state()).
WillOnce(Return(DataTypeManager::STOPPED));
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
service_->Initialize();
EXPECT_TRUE(service_->HasUnrecoverableError());
}
TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
// Preload the tokens.
TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
GaiaConstants::kSyncService, "sync_token");
service_->fail_initial_download();
service_->Initialize();
EXPECT_FALSE(service_->sync_initialized());
EXPECT_FALSE(service_->GetBackendForTest());
}