// Copyright (c) 2011 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/net/gaia/token_service.h" #include "chrome/browser/prefs/pref_service.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_factory_mock.h" #include "chrome/browser/sync/profile_sync_test_util.h" #include "chrome/browser/sync/test_profile_sync_service.h" #include "chrome/common/net/gaia/gaia_auth_consumer.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_profile.h" #include "content/browser/browser_thread.h" #include "content/common/notification_type.h" #include "testing/gmock/include/gmock/gmock.h" using browser_sync::DataTypeManager; using browser_sync::DataTypeManagerMock; using testing::_; using testing::AnyNumber; using testing::DoAll; using testing::InvokeArgument; using testing::Mock; using testing::Return; ACTION_P(InvokeCallback, callback_result) { arg0->Run(callback_result); delete arg0; } // TODO(skrul) This test fails on the mac. See http://crbug.com/33443 #if defined(OS_MACOSX) #define SKIP_MACOSX(test) DISABLED_##test #else #define SKIP_MACOSX(test) test #endif // TODO(chron): Test not using cros_user flag and use signin_ class ProfileSyncServiceStartupTest : public testing::Test { public: ProfileSyncServiceStartupTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} virtual ~ProfileSyncServiceStartupTest() { // The PSS has some deletes that are scheduled on the main thread // so we must delete the service and run the message loop. service_.reset(); MessageLoop::current()->RunAllPending(); } virtual void SetUp() { profile_.CreateRequestContext(); service_.reset(new TestProfileSyncService(&factory_, &profile_, "test", true, NULL)); service_->AddObserver(&observer_); service_->set_synchronous_sync_configuration(); } virtual void TearDown() { service_->RemoveObserver(&observer_); { // The request context gets deleted on the I/O thread. To prevent a leak // supply one here. BrowserThread io_thread(BrowserThread::IO, MessageLoop::current()); profile_.ResetRequestContext(); } MessageLoop::current()->RunAllPending(); } protected: DataTypeManagerMock* SetUpDataTypeManager() { DataTypeManagerMock* data_type_manager = new DataTypeManagerMock(); EXPECT_CALL(factory_, CreateDataTypeManager(_, _)). WillOnce(Return(data_type_manager)); return data_type_manager; } MessageLoop message_loop_; BrowserThread ui_thread_; TestingProfile profile_; ProfileSyncFactoryMock factory_; scoped_ptr<TestProfileSyncService> service_; ProfileSyncServiceObserverMock observer_; }; TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFirstTime)) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_)).Times(0); // We've never completed startup. profile_.GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted); // 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(3); EXPECT_CALL(*data_type_manager, state()). 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. profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); syncable::ModelTypeSet set; set.insert(syncable::BOOKMARKS); service_->OnUserChoseDatatypes(false, set); } TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartNormal)) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_)).Times(2); EXPECT_CALL(*data_type_manager, state()). WillOnce(Return(DataTypeManager::CONFIGURED)); EXPECT_CALL(*data_type_manager, Stop()).Times(1); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); // Pre load the tokens profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); service_->Initialize(); } TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(ManagedStartup)) { // Disable sync through policy. profile_.GetPrefs()->SetBoolean(prefs::kSyncManaged, true); EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).Times(0); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); // Service should not be started by Initialize() since it's managed. profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); service_->Initialize(); } TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(SwitchManaged)) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_)).Times(2); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); 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_, CreateDataTypeManager(_, _)).Times(0); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); profile_.GetPrefs()->ClearPref(prefs::kSyncManaged); } TEST_F(ProfileSyncServiceStartupTest, ClearServerData) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_)).Times(2); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); service_->Initialize(); Mock::VerifyAndClearExpectations(data_type_manager); // Success can overwrite failure, failure cannot overwrite success. We want // this behavior because once clear has succeeded, sync gets disabled, and // we don't care about any subsequent failures (e.g. timeouts) service_->ResetClearServerDataState(); EXPECT_TRUE(ProfileSyncService::CLEAR_NOT_STARTED == service_->GetClearServerDataState()); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); service_->OnClearServerDataFailed(); EXPECT_TRUE(ProfileSyncService::CLEAR_FAILED == service_->GetClearServerDataState()); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); service_->OnClearServerDataSucceeded(); EXPECT_TRUE(ProfileSyncService::CLEAR_SUCCEEDED == service_->GetClearServerDataState()); service_->OnClearServerDataFailed(); EXPECT_TRUE(ProfileSyncService::CLEAR_SUCCEEDED == service_->GetClearServerDataState()); // Now test the timeout states service_->ResetClearServerDataState(); EXPECT_TRUE(ProfileSyncService::CLEAR_NOT_STARTED == service_->GetClearServerDataState()); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); service_->OnClearServerDataTimeout(); EXPECT_TRUE(ProfileSyncService::CLEAR_FAILED == service_->GetClearServerDataState()); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); service_->OnClearServerDataSucceeded(); EXPECT_TRUE(ProfileSyncService::CLEAR_SUCCEEDED == service_->GetClearServerDataState()); service_->OnClearServerDataFailed(); EXPECT_TRUE(ProfileSyncService::CLEAR_SUCCEEDED == service_->GetClearServerDataState()); // Test the pending state, doesn't matter what state // the back end syncmgr returns EXPECT_CALL(*data_type_manager, state()). WillOnce(Return(DataTypeManager::STOPPED)); service_->ResetClearServerDataState(); service_->ClearServerData(); EXPECT_TRUE(ProfileSyncService::CLEAR_CLEARING == service_->GetClearServerDataState()); // Stop the timer and reset the state EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); service_->OnClearServerDataSucceeded(); service_->ResetClearServerDataState(); } TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFailure)) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); DataTypeManager::ConfigureResult configure_result = DataTypeManager::ASSOCIATION_FAILED; browser_sync::DataTypeManager::ConfigureResultWithErrorLocation result( configure_result, FROM_HERE, syncable::ModelTypeSet()); EXPECT_CALL(*data_type_manager, Configure(_)). WillRepeatedly(DoAll(NotifyFromDataTypeManager(data_type_manager, NotificationType::SYNC_CONFIGURE_START), NotifyFromDataTypeManagerWithResult(data_type_manager, NotificationType::SYNC_CONFIGURE_DONE, &result))); EXPECT_CALL(*data_type_manager, state()). WillOnce(Return(DataTypeManager::STOPPED)); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); profile_.GetTokenService()->IssueAuthTokenForTest( GaiaConstants::kSyncService, "sync_token"); service_->Initialize(); EXPECT_TRUE(service_->unrecoverable_error_detected()); }