profile_sync_service_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/basictypes.h" 6#include "base/command_line.h" 7#include "base/compiler_specific.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/run_loop.h" 10#include "base/strings/utf_string_conversions.h" 11#include "base/values.h" 12#include "chrome/browser/invalidation/fake_invalidation_service.h" 13#include "chrome/browser/invalidation/invalidation_service_factory.h" 14#include "chrome/browser/signin/fake_profile_oauth2_token_service.h" 15#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h" 16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 17#include "chrome/browser/signin/signin_manager_factory.h" 18#include "chrome/browser/sync/glue/sync_backend_host_mock.h" 19#include "chrome/browser/sync/managed_user_signin_manager_wrapper.h" 20#include "chrome/browser/sync/profile_sync_components_factory_mock.h" 21#include "chrome/common/chrome_switches.h" 22#include "chrome/common/pref_names.h" 23#include "chrome/test/base/testing_browser_process.h" 24#include "chrome/test/base/testing_pref_service_syncable.h" 25#include "chrome/test/base/testing_profile.h" 26#include "chrome/test/base/testing_profile_manager.h" 27#include "components/signin/core/browser/signin_manager.h" 28#include "components/sync_driver/data_type_manager_impl.h" 29#include "components/sync_driver/pref_names.h" 30#include "content/public/test/test_browser_thread_bundle.h" 31#include "google_apis/gaia/gaia_constants.h" 32#include "testing/gmock/include/gmock/gmock.h" 33#include "testing/gtest/include/gtest/gtest.h" 34 35namespace browser_sync { 36 37namespace { 38 39ACTION(ReturnNewDataTypeManager) { 40 return new browser_sync::DataTypeManagerImpl(base::Closure(), 41 arg0, 42 arg1, 43 arg2, 44 arg3, 45 arg4, 46 arg5); 47} 48 49using testing::StrictMock; 50using testing::_; 51 52class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver { 53 public: 54 explicit TestProfileSyncServiceObserver(ProfileSyncService* service) 55 : service_(service), first_setup_in_progress_(false) {} 56 virtual void OnStateChanged() OVERRIDE { 57 first_setup_in_progress_ = service_->FirstSetupInProgress(); 58 } 59 bool first_setup_in_progress() const { return first_setup_in_progress_; } 60 private: 61 ProfileSyncService* service_; 62 bool first_setup_in_progress_; 63}; 64 65// A variant of the SyncBackendHostMock that won't automatically 66// call back when asked to initialized. Allows us to test things 67// that could happen while backend init is in progress. 68class SyncBackendHostNoReturn : public SyncBackendHostMock { 69 virtual void Initialize( 70 SyncFrontend* frontend, 71 scoped_ptr<base::Thread> sync_thread, 72 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, 73 const GURL& service_url, 74 const syncer::SyncCredentials& credentials, 75 bool delete_sync_data_folder, 76 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory, 77 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler, 78 syncer::ReportUnrecoverableErrorFunction 79 report_unrecoverable_error_function, 80 syncer::NetworkResources* network_resources) OVERRIDE {} 81}; 82 83ACTION(ReturnNewSyncBackendHostMock) { 84 return new browser_sync::SyncBackendHostMock(); 85} 86 87ACTION(ReturnNewSyncBackendHostNoReturn) { 88 return new browser_sync::SyncBackendHostNoReturn(); 89} 90 91// A test harness that uses a real ProfileSyncService and in most cases a 92// MockSyncBackendHost. 93// 94// This is useful if we want to test the ProfileSyncService and don't care about 95// testing the SyncBackendHost. 96class ProfileSyncServiceTest : public ::testing::Test { 97 protected: 98 ProfileSyncServiceTest() 99 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 100 profile_manager_(TestingBrowserProcess::GetGlobal()) {} 101 virtual ~ProfileSyncServiceTest() {} 102 103 virtual void SetUp() OVERRIDE { 104 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 105 switches::kSyncDeferredStartupTimeoutSeconds, "0"); 106 107#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 108 CommandLine::ForCurrentProcess()->AppendSwitch( 109 switches::kSyncEnableBackupRollback); 110#endif 111 112 CHECK(profile_manager_.SetUp()); 113 114 TestingProfile::TestingFactories testing_facotries; 115 testing_facotries.push_back( 116 std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(), 117 BuildAutoIssuingFakeProfileOAuth2TokenService)); 118 testing_facotries.push_back( 119 std::make_pair( 120 invalidation::InvalidationServiceFactory::GetInstance(), 121 invalidation::FakeInvalidationService::Build)); 122 123 profile_ = profile_manager_.CreateTestingProfile( 124 "sync-service-test", scoped_ptr<PrefServiceSyncable>(), 125 base::UTF8ToUTF16("sync-service-test"), 0, std::string(), 126 testing_facotries); 127 } 128 129 virtual void TearDown() OVERRIDE { 130 // Kill the service before the profile. 131 if (service_) 132 service_->Shutdown(); 133 134 service_.reset(); 135 } 136 137 void IssueTestTokens() { 138 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) 139 ->UpdateCredentials("test", "oauth2_login_token"); 140 } 141 142 void CreateService(ProfileSyncServiceStartBehavior behavior) { 143 SigninManagerBase* signin = 144 SigninManagerFactory::GetForProfile(profile_); 145 signin->SetAuthenticatedUsername("test"); 146 ProfileOAuth2TokenService* oauth2_token_service = 147 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); 148 components_factory_ = new StrictMock<ProfileSyncComponentsFactoryMock>(); 149 service_.reset(new ProfileSyncService( 150 components_factory_, 151 profile_, 152 new ManagedUserSigninManagerWrapper(profile_, signin), 153 oauth2_token_service, 154 behavior)); 155 } 156 157#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 158 void CreateServiceWithoutSignIn() { 159 CreateService(browser_sync::MANUAL_START); 160 SigninManagerFactory::GetForProfile(profile())->SignOut(); 161 service()->SetBackupStartDelayForTest( 162 base::TimeDelta::FromMilliseconds(100)); 163 } 164#endif 165 166 void ShutdownAndDeleteService() { 167 if (service_) 168 service_->Shutdown(); 169 service_.reset(); 170 } 171 172 void Initialize() { 173 service_->Initialize(); 174 } 175 176 void ExpectDataTypeManagerCreation(int times) { 177 EXPECT_CALL(*components_factory_, CreateDataTypeManager(_, _, _, _, _, _)) 178 .Times(times) 179 .WillRepeatedly(ReturnNewDataTypeManager()); 180 } 181 182 void ExpectSyncBackendHostCreation(int times) { 183 EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _, _, _)) 184 .Times(times) 185 .WillRepeatedly(ReturnNewSyncBackendHostMock()); 186 } 187 188 void PrepareDelayedInitSyncBackendHost() { 189 EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _, _, _)). 190 WillOnce(ReturnNewSyncBackendHostNoReturn()); 191 } 192 193 TestingProfile* profile() { 194 return profile_; 195 } 196 197 ProfileSyncService* service() { 198 return service_.get(); 199 } 200 201 ProfileSyncComponentsFactoryMock* components_factory() { 202 return components_factory_; 203 } 204 205 private: 206 content::TestBrowserThreadBundle thread_bundle_; 207 TestingProfileManager profile_manager_; 208 TestingProfile* profile_; 209 scoped_ptr<ProfileSyncService> service_; 210 211 // Pointer to the components factory. Not owned. May be null. 212 ProfileSyncComponentsFactoryMock* components_factory_; 213}; 214 215// Verify that the server URLs are sane. 216TEST_F(ProfileSyncServiceTest, InitialState) { 217 CreateService(browser_sync::AUTO_START); 218 Initialize(); 219 const std::string& url = service()->sync_service_url().spec(); 220 EXPECT_TRUE(url == ProfileSyncService::kSyncServerUrl || 221 url == ProfileSyncService::kDevServerUrl); 222} 223 224// Verify a successful initialization. 225TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) { 226 profile()->GetTestingPrefService()->SetManagedPref( 227 sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(false)); 228 IssueTestTokens(); 229 CreateService(browser_sync::AUTO_START); 230 ExpectDataTypeManagerCreation(1); 231 ExpectSyncBackendHostCreation(1); 232 Initialize(); 233 EXPECT_FALSE(service()->IsManaged()); 234 EXPECT_TRUE(service()->sync_initialized()); 235 EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode()); 236} 237 238 239// Verify that the SetSetupInProgress function call updates state 240// and notifies observers. 241TEST_F(ProfileSyncServiceTest, SetupInProgress) { 242 CreateService(browser_sync::AUTO_START); 243 Initialize(); 244 245 TestProfileSyncServiceObserver observer(service()); 246 service()->AddObserver(&observer); 247 248 service()->SetSetupInProgress(true); 249 EXPECT_TRUE(observer.first_setup_in_progress()); 250 service()->SetSetupInProgress(false); 251 EXPECT_FALSE(observer.first_setup_in_progress()); 252 253 service()->RemoveObserver(&observer); 254} 255 256// Verify that disable by enterprise policy works. 257TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) { 258 profile()->GetTestingPrefService()->SetManagedPref( 259 sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true)); 260 IssueTestTokens(); 261 CreateService(browser_sync::AUTO_START); 262 Initialize(); 263 EXPECT_TRUE(service()->IsManaged()); 264 EXPECT_FALSE(service()->sync_initialized()); 265} 266 267// Verify that disable by enterprise policy works even after the backend has 268// been initialized. 269TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) { 270 IssueTestTokens(); 271 CreateService(browser_sync::AUTO_START); 272 ExpectDataTypeManagerCreation(1); 273 ExpectSyncBackendHostCreation(1); 274 Initialize(); 275 276 EXPECT_FALSE(service()->IsManaged()); 277 EXPECT_TRUE(service()->sync_initialized()); 278 279 profile()->GetTestingPrefService()->SetManagedPref( 280 sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true)); 281 282 EXPECT_TRUE(service()->IsManaged()); 283 EXPECT_FALSE(service()->sync_initialized()); 284} 285 286// Exercies the ProfileSyncService's code paths related to getting shut down 287// before the backend initialize call returns. 288TEST_F(ProfileSyncServiceTest, AbortedByShutdown) { 289 CreateService(browser_sync::AUTO_START); 290 PrepareDelayedInitSyncBackendHost(); 291 292 IssueTestTokens(); 293 Initialize(); 294 EXPECT_FALSE(service()->sync_initialized()); 295 296 ShutdownAndDeleteService(); 297} 298 299// Test StopAndSuppress() before we've initialized the backend. 300TEST_F(ProfileSyncServiceTest, EarlyStopAndSuppress) { 301 CreateService(browser_sync::AUTO_START); 302 IssueTestTokens(); 303 304 service()->StopAndSuppress(); 305 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean( 306 sync_driver::prefs::kSyncSuppressStart)); 307 308 // Because of supression, this should fail. 309 Initialize(); 310 EXPECT_FALSE(service()->sync_initialized()); 311 312 // Remove suppression. This should be enough to allow init to happen. 313 ExpectDataTypeManagerCreation(1); 314 ExpectSyncBackendHostCreation(1); 315 service()->UnsuppressAndStart(); 316 EXPECT_TRUE(service()->sync_initialized()); 317 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( 318 sync_driver::prefs::kSyncSuppressStart)); 319} 320 321// Test StopAndSuppress() after we've initialized the backend. 322TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) { 323 CreateService(browser_sync::AUTO_START); 324 IssueTestTokens(); 325 ExpectDataTypeManagerCreation(1); 326 ExpectSyncBackendHostCreation(1); 327 Initialize(); 328 329 EXPECT_TRUE(service()->sync_initialized()); 330 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( 331 sync_driver::prefs::kSyncSuppressStart)); 332 333 testing::Mock::VerifyAndClearExpectations(components_factory()); 334 335 service()->StopAndSuppress(); 336 EXPECT_FALSE(service()->sync_initialized()); 337 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean( 338 sync_driver::prefs::kSyncSuppressStart)); 339 340 ExpectDataTypeManagerCreation(1); 341 ExpectSyncBackendHostCreation(1); 342 343 service()->UnsuppressAndStart(); 344 EXPECT_TRUE(service()->sync_initialized()); 345 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( 346 sync_driver::prefs::kSyncSuppressStart)); 347} 348 349// Certain ProfileSyncService tests don't apply to Chrome OS, for example 350// things that deal with concepts like "signing out" and policy. 351#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 352TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOutDesktop) { 353 CreateService(browser_sync::AUTO_START); 354 ExpectDataTypeManagerCreation(2); 355 ExpectSyncBackendHostCreation(2); 356 IssueTestTokens(); 357 Initialize(); 358 359 EXPECT_TRUE(service()->sync_initialized()); 360 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( 361 sync_driver::prefs::kSyncSuppressStart)); 362 EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode()); 363 364 SigninManagerFactory::GetForProfile(profile())->SignOut(); 365 EXPECT_TRUE(service()->sync_initialized()); 366 EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode()); 367} 368#elif !defined (OS_CHROMEOS) 369TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) { 370 CreateService(browser_sync::AUTO_START); 371 ExpectDataTypeManagerCreation(1); 372 ExpectSyncBackendHostCreation(1); 373 IssueTestTokens(); 374 Initialize(); 375 376 EXPECT_TRUE(service()->sync_initialized()); 377 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean( 378 sync_driver::prefs::kSyncSuppressStart)); 379 380 SigninManagerFactory::GetForProfile(profile())->SignOut(); 381 EXPECT_FALSE(service()->sync_initialized()); 382} 383#endif // !defined(OS_CHROMEOS) 384 385TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) { 386 CreateService(browser_sync::AUTO_START); 387 IssueTestTokens(); 388 ExpectDataTypeManagerCreation(1); 389 ExpectSyncBackendHostCreation(1); 390 Initialize(); 391 392 // Initial status. 393 ProfileSyncService::SyncTokenStatus token_status = 394 service()->GetSyncTokenStatus(); 395 EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status); 396 EXPECT_TRUE(token_status.connection_status_update_time.is_null()); 397 EXPECT_TRUE(token_status.token_request_time.is_null()); 398 EXPECT_TRUE(token_status.token_receive_time.is_null()); 399 400 // Simulate an auth error. 401 service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR); 402 403 // The token request will take the form of a posted task. Run it. 404 base::RunLoop loop; 405 loop.RunUntilIdle(); 406 407 token_status = service()->GetSyncTokenStatus(); 408 EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status); 409 EXPECT_FALSE(token_status.connection_status_update_time.is_null()); 410 EXPECT_FALSE(token_status.token_request_time.is_null()); 411 EXPECT_FALSE(token_status.token_receive_time.is_null()); 412 EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), 413 token_status.last_get_token_error); 414 EXPECT_TRUE(token_status.next_token_request_time.is_null()); 415 416 // Simulate successful connection. 417 service()->OnConnectionStatusChange(syncer::CONNECTION_OK); 418 token_status = service()->GetSyncTokenStatus(); 419 EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status); 420} 421 422#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 423void QuitLoop() { 424 base::MessageLoop::current()->Quit(); 425} 426 427TEST_F(ProfileSyncServiceTest, StartBackup) { 428 CreateServiceWithoutSignIn(); 429 ExpectDataTypeManagerCreation(1); 430 ExpectSyncBackendHostCreation(1); 431 Initialize(); 432 EXPECT_EQ(ProfileSyncService::IDLE, service()->backend_mode()); 433 base::MessageLoop::current()->PostDelayedTask( 434 FROM_HERE, base::Bind(&QuitLoop), 435 base::TimeDelta::FromMilliseconds(100)); 436 base::MessageLoop::current()->Run(); 437 EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode()); 438} 439 440TEST_F(ProfileSyncServiceTest, BackupAfterSyncDisabled) { 441 CreateService(browser_sync::MANUAL_START); 442 service()->SetSyncSetupCompleted(); 443 ExpectDataTypeManagerCreation(2); 444 ExpectSyncBackendHostCreation(2); 445 IssueTestTokens(); 446 Initialize(); 447 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoop)); 448 EXPECT_TRUE(service()->sync_initialized()); 449 EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode()); 450 451 syncer::SyncProtocolError client_cmd; 452 client_cmd.action = syncer::DISABLE_SYNC_ON_CLIENT; 453 service()->OnActionableError(client_cmd); 454 EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode()); 455} 456 457TEST_F(ProfileSyncServiceTest, RollbackThenBackup) { 458 CreateService(browser_sync::MANUAL_START); 459 service()->SetSyncSetupCompleted(); 460 ExpectDataTypeManagerCreation(3); 461 ExpectSyncBackendHostCreation(3); 462 IssueTestTokens(); 463 Initialize(); 464 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoop)); 465 EXPECT_TRUE(service()->sync_initialized()); 466 EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode()); 467 468 syncer::SyncProtocolError client_cmd; 469 client_cmd.action = syncer::DISABLE_SYNC_AND_ROLLBACK; 470 service()->OnActionableError(client_cmd); 471 EXPECT_TRUE(service()->sync_initialized()); 472 EXPECT_EQ(ProfileSyncService::ROLLBACK, service()->backend_mode()); 473 474 client_cmd.action = syncer::ROLLBACK_DONE; 475 service()->OnActionableError(client_cmd); 476 EXPECT_TRUE(service()->sync_initialized()); 477 EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode()); 478} 479#endif 480 481} // namespace 482} // namespace browser_sync 483