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 "chrome/browser/sync/test/integration/sync_test.h" 6 7 #include <vector> 8 9 #include "base/basictypes.h" 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/path_service.h" 15 #include "base/process/launch.h" 16 #include "base/strings/string_util.h" 17 #include "base/strings/stringprintf.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "base/synchronization/waitable_event.h" 20 #include "base/test/test_timeouts.h" 21 #include "base/threading/platform_thread.h" 22 #include "base/values.h" 23 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 24 #include "chrome/browser/history/history_service_factory.h" 25 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" 26 #include "chrome/browser/lifetime/application_lifetime.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/profiles/profile_manager.h" 29 #include "chrome/browser/search_engines/template_url_service_factory.h" 30 #include "chrome/browser/signin/profile_identity_provider.h" 31 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 32 #include "chrome/browser/signin/signin_manager_factory.h" 33 #include "chrome/browser/sync/glue/invalidation_helper.h" 34 #include "chrome/browser/sync/profile_sync_service.h" 35 #include "chrome/browser/sync/profile_sync_service_factory.h" 36 #include "chrome/browser/sync/test/integration/fake_server_invalidation_service.h" 37 #include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h" 38 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" 39 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" 40 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" 41 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" 42 #include "chrome/browser/ui/browser.h" 43 #include "chrome/browser/ui/browser_finder.h" 44 #include "chrome/browser/ui/host_desktop.h" 45 #include "chrome/browser/ui/tabs/tab_strip_model.h" 46 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" 47 #include "chrome/common/chrome_paths.h" 48 #include "chrome/common/chrome_switches.h" 49 #include "chrome/test/base/testing_browser_process.h" 50 #include "chrome/test/base/ui_test_utils.h" 51 #include "components/bookmarks/test/bookmark_test_helpers.h" 52 #include "components/google/core/browser/google_url_tracker.h" 53 #include "components/invalidation/invalidation_service.h" 54 #include "components/invalidation/invalidation_switches.h" 55 #include "components/invalidation/p2p_invalidation_service.h" 56 #include "components/invalidation/p2p_invalidator.h" 57 #include "components/invalidation/profile_invalidation_provider.h" 58 #include "components/keyed_service/core/keyed_service.h" 59 #include "components/os_crypt/os_crypt.h" 60 #include "components/search_engines/template_url_service.h" 61 #include "components/signin/core/browser/signin_manager.h" 62 #include "content/public/browser/web_contents.h" 63 #include "content/public/test/test_browser_thread.h" 64 #include "google_apis/gaia/gaia_urls.h" 65 #include "net/base/escape.h" 66 #include "net/base/load_flags.h" 67 #include "net/base/network_change_notifier.h" 68 #include "net/cookies/cookie_monster.h" 69 #include "net/proxy/proxy_config.h" 70 #include "net/proxy/proxy_config_service_fixed.h" 71 #include "net/proxy/proxy_service.h" 72 #include "net/test/spawned_test_server/spawned_test_server.h" 73 #include "net/url_request/test_url_fetcher_factory.h" 74 #include "net/url_request/url_fetcher.h" 75 #include "net/url_request/url_fetcher_delegate.h" 76 #include "net/url_request/url_request_context.h" 77 #include "net/url_request/url_request_context_getter.h" 78 #include "sync/engine/sync_scheduler_impl.h" 79 #include "sync/protocol/sync.pb.h" 80 #include "sync/test/fake_server/fake_server.h" 81 #include "sync/test/fake_server/fake_server_network_resources.h" 82 #include "url/gurl.h" 83 84 #if defined(OS_CHROMEOS) 85 #include "chromeos/chromeos_switches.h" 86 #endif 87 88 using content::BrowserThread; 89 90 namespace switches { 91 const char kPasswordFileForTest[] = "password-file-for-test"; 92 const char kSyncUserForTest[] = "sync-user-for-test"; 93 const char kSyncPasswordForTest[] = "sync-password-for-test"; 94 const char kSyncServerCommandLine[] = "sync-server-command-line"; 95 } 96 97 namespace { 98 99 // Helper class that checks whether a sync test server is running or not. 100 class SyncServerStatusChecker : public net::URLFetcherDelegate { 101 public: 102 SyncServerStatusChecker() : running_(false) {} 103 104 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { 105 std::string data; 106 source->GetResponseAsString(&data); 107 running_ = 108 (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && 109 source->GetResponseCode() == 200 && data.find("ok") == 0); 110 base::MessageLoop::current()->Quit(); 111 } 112 113 bool running() const { return running_; } 114 115 private: 116 bool running_; 117 }; 118 119 bool IsEncryptionComplete(const ProfileSyncService* service) { 120 return service->EncryptEverythingEnabled() && !service->encryption_pending(); 121 } 122 123 // Helper class to wait for encryption to complete. 124 class EncryptionChecker : public SingleClientStatusChangeChecker { 125 public: 126 explicit EncryptionChecker(ProfileSyncService* service) 127 : SingleClientStatusChangeChecker(service) {} 128 129 virtual bool IsExitConditionSatisfied() OVERRIDE { 130 return IsEncryptionComplete(service()); 131 } 132 133 virtual std::string GetDebugMessage() const OVERRIDE { 134 return "Encryption"; 135 } 136 }; 137 138 void SetupNetworkCallback( 139 base::WaitableEvent* done, 140 net::URLRequestContextGetter* url_request_context_getter) { 141 url_request_context_getter->GetURLRequestContext()-> 142 set_cookie_store(new net::CookieMonster(NULL, NULL)); 143 done->Signal(); 144 } 145 146 void SetProxyConfigCallback( 147 base::WaitableEvent* done, 148 net::URLRequestContextGetter* url_request_context_getter, 149 const net::ProxyConfig& proxy_config) { 150 net::ProxyService* proxy_service = 151 url_request_context_getter->GetURLRequestContext()->proxy_service(); 152 proxy_service->ResetConfigService( 153 new net::ProxyConfigServiceFixed(proxy_config)); 154 done->Signal(); 155 } 156 157 KeyedService* BuildFakeServerProfileInvalidationProvider( 158 content::BrowserContext* context) { 159 return new invalidation::ProfileInvalidationProvider( 160 scoped_ptr<invalidation::InvalidationService>( 161 new fake_server::FakeServerInvalidationService)); 162 } 163 164 KeyedService* BuildP2PProfileInvalidationProvider( 165 content::BrowserContext* context, 166 syncer::P2PNotificationTarget notification_target) { 167 Profile* profile = static_cast<Profile*>(context); 168 return new invalidation::ProfileInvalidationProvider( 169 scoped_ptr<invalidation::InvalidationService>( 170 new invalidation::P2PInvalidationService( 171 scoped_ptr<IdentityProvider>(new ProfileIdentityProvider( 172 SigninManagerFactory::GetForProfile(profile), 173 ProfileOAuth2TokenServiceFactory::GetForProfile(profile), 174 LoginUIServiceFactory::GetForProfile(profile))), 175 profile->GetRequestContext(), 176 notification_target))); 177 } 178 179 KeyedService* BuildSelfNotifyingP2PProfileInvalidationProvider( 180 content::BrowserContext* context) { 181 return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_ALL); 182 } 183 184 KeyedService* BuildRealisticP2PProfileInvalidationProvider( 185 content::BrowserContext* context) { 186 return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_OTHERS); 187 } 188 189 } // namespace 190 191 SyncTest::SyncTest(TestType test_type) 192 : test_type_(test_type), 193 server_type_(SERVER_TYPE_UNDECIDED), 194 num_clients_(-1), 195 use_verifier_(true), 196 notifications_enabled_(true), 197 test_server_handle_(base::kNullProcessHandle) { 198 sync_datatype_helper::AssociateWithTest(this); 199 switch (test_type_) { 200 case SINGLE_CLIENT: 201 case SINGLE_CLIENT_LEGACY: { 202 num_clients_ = 1; 203 break; 204 } 205 case TWO_CLIENT: 206 case TWO_CLIENT_LEGACY: { 207 num_clients_ = 2; 208 break; 209 } 210 case MULTIPLE_CLIENT: { 211 num_clients_ = 3; 212 break; 213 } 214 } 215 } 216 217 SyncTest::~SyncTest() {} 218 219 void SyncTest::SetUp() { 220 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 221 if (cl->HasSwitch(switches::kPasswordFileForTest)) { 222 ReadPasswordFile(); 223 } else if (cl->HasSwitch(switches::kSyncUserForTest) && 224 cl->HasSwitch(switches::kSyncPasswordForTest)) { 225 username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest); 226 password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest); 227 } else { 228 username_ = "user (at) gmail.com"; 229 password_ = "password"; 230 } 231 232 if (username_.empty() || password_.empty()) 233 LOG(FATAL) << "Cannot run sync tests without GAIA credentials."; 234 235 // Sets |server_type_| if it wasn't specified by the test. 236 DecideServerType(); 237 238 // Mock the Mac Keychain service. The real Keychain can block on user input. 239 #if defined(OS_MACOSX) 240 OSCrypt::UseMockKeychain(true); 241 #endif 242 243 // Start up a sync test server if one is needed and setup mock gaia responses. 244 // Note: This must be done prior to the call to SetupClients() because we want 245 // the mock gaia responses to be available before GaiaUrls is initialized. 246 SetUpTestServerIfRequired(); 247 248 // Yield control back to the InProcessBrowserTest framework. 249 InProcessBrowserTest::SetUp(); 250 } 251 252 void SyncTest::TearDown() { 253 // Clear any mock gaia responses that might have been set. 254 ClearMockGaiaResponses(); 255 256 // Allow the InProcessBrowserTest framework to perform its tear down. 257 InProcessBrowserTest::TearDown(); 258 259 // Stop the local python test server. This is a no-op if one wasn't started. 260 TearDownLocalPythonTestServer(); 261 262 // Stop the local sync test server. This is a no-op if one wasn't started. 263 TearDownLocalTestServer(); 264 265 fake_server_.reset(); 266 } 267 268 void SyncTest::SetUpCommandLine(base::CommandLine* cl) { 269 AddTestSwitches(cl); 270 AddOptionalTypesToCommandLine(cl); 271 272 #if defined(OS_CHROMEOS) 273 cl->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests); 274 #endif 275 } 276 277 void SyncTest::AddTestSwitches(base::CommandLine* cl) { 278 // Disable non-essential access of external network resources. 279 if (!cl->HasSwitch(switches::kDisableBackgroundNetworking)) 280 cl->AppendSwitch(switches::kDisableBackgroundNetworking); 281 282 if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) 283 cl->AppendSwitch(switches::kSyncShortInitialRetryOverride); 284 } 285 286 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine* cl) {} 287 288 // static 289 Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) { 290 base::FilePath path; 291 PathService::Get(chrome::DIR_USER_DATA, &path); 292 path = path.Append(name); 293 294 if (!base::PathExists(path)) 295 CHECK(base::CreateDirectory(path)); 296 297 Profile* profile = 298 Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS); 299 g_browser_process->profile_manager()->RegisterTestingProfile(profile, 300 true, 301 true); 302 return profile; 303 } 304 305 Profile* SyncTest::GetProfile(int index) { 306 if (profiles_.empty()) 307 LOG(FATAL) << "SetupClients() has not yet been called."; 308 if (index < 0 || index >= static_cast<int>(profiles_.size())) 309 LOG(FATAL) << "GetProfile(): Index is out of bounds."; 310 return profiles_[index]; 311 } 312 313 Browser* SyncTest::GetBrowser(int index) { 314 if (browsers_.empty()) 315 LOG(FATAL) << "SetupClients() has not yet been called."; 316 if (index < 0 || index >= static_cast<int>(browsers_.size())) 317 LOG(FATAL) << "GetBrowser(): Index is out of bounds."; 318 return browsers_[index]; 319 } 320 321 ProfileSyncServiceHarness* SyncTest::GetClient(int index) { 322 if (clients_.empty()) 323 LOG(FATAL) << "SetupClients() has not yet been called."; 324 if (index < 0 || index >= static_cast<int>(clients_.size())) 325 LOG(FATAL) << "GetClient(): Index is out of bounds."; 326 return clients_[index]; 327 } 328 329 ProfileSyncService* SyncTest::GetSyncService(int index) { 330 return ProfileSyncServiceFactory::GetForProfile(GetProfile(index)); 331 } 332 333 std::vector<ProfileSyncService*> SyncTest::GetSyncServices() { 334 std::vector<ProfileSyncService*> services; 335 for (int i = 0; i < num_clients(); ++i) { 336 services.push_back(GetSyncService(i)); 337 } 338 return services; 339 } 340 341 Profile* SyncTest::verifier() { 342 if (verifier_ == NULL) 343 LOG(FATAL) << "SetupClients() has not yet been called."; 344 return verifier_; 345 } 346 347 void SyncTest::DisableVerifier() { 348 use_verifier_ = false; 349 } 350 351 bool SyncTest::SetupClients() { 352 if (num_clients_ <= 0) 353 LOG(FATAL) << "num_clients_ incorrectly initialized."; 354 if (!profiles_.empty() || !browsers_.empty() || !clients_.empty()) 355 LOG(FATAL) << "SetupClients() has already been called."; 356 357 // Create the required number of sync profiles, browsers and clients. 358 profiles_.resize(num_clients_); 359 browsers_.resize(num_clients_); 360 clients_.resize(num_clients_); 361 invalidation_forwarders_.resize(num_clients_); 362 fake_server_invalidation_services_.resize(num_clients_); 363 for (int i = 0; i < num_clients_; ++i) { 364 InitializeInstance(i); 365 } 366 367 // Create the verifier profile. 368 verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier")); 369 test::WaitForBookmarkModelToLoad( 370 BookmarkModelFactory::GetForProfile(verifier())); 371 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 372 verifier(), Profile::EXPLICIT_ACCESS)); 373 ui_test_utils::WaitForTemplateURLServiceToLoad( 374 TemplateURLServiceFactory::GetForProfile(verifier())); 375 return (verifier_ != NULL); 376 } 377 378 void SyncTest::InitializeInstance(int index) { 379 profiles_[index] = MakeProfile( 380 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index)); 381 EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile " 382 << index << "."; 383 384 browsers_[index] = new Browser(Browser::CreateParams( 385 GetProfile(index), chrome::GetActiveDesktop())); 386 EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser " 387 << index << "."; 388 389 390 // Make sure the ProfileSyncService has been created before creating the 391 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to 392 // already exist. 393 ProfileSyncService* profile_sync_service = 394 ProfileSyncServiceFactory::GetForProfile(GetProfile(index)); 395 396 SetupNetwork(GetProfile(index)->GetRequestContext()); 397 398 if (server_type_ == IN_PROCESS_FAKE_SERVER) { 399 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer. 400 profile_sync_service->OverrideNetworkResourcesForTest( 401 make_scoped_ptr<syncer::NetworkResources>( 402 new fake_server::FakeServerNetworkResources(fake_server_.get()))); 403 } 404 405 clients_[index] = 406 ProfileSyncServiceHarness::Create( 407 GetProfile(index), 408 username_, 409 password_); 410 EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client " 411 << index << "."; 412 InitializeInvalidations(index); 413 414 test::WaitForBookmarkModelToLoad( 415 BookmarkModelFactory::GetForProfile(GetProfile(index))); 416 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 417 GetProfile(index), Profile::EXPLICIT_ACCESS)); 418 ui_test_utils::WaitForTemplateURLServiceToLoad( 419 TemplateURLServiceFactory::GetForProfile(GetProfile(index))); 420 } 421 422 void SyncTest::InitializeInvalidations(int index) { 423 if (server_type_ == IN_PROCESS_FAKE_SERVER) { 424 CHECK(fake_server_.get()); 425 fake_server::FakeServerInvalidationService* invalidation_service = 426 static_cast<fake_server::FakeServerInvalidationService*>( 427 static_cast<invalidation::ProfileInvalidationProvider*>( 428 invalidation::ProfileInvalidationProviderFactory:: 429 GetInstance()->SetTestingFactoryAndUse( 430 GetProfile(index), 431 BuildFakeServerProfileInvalidationProvider))-> 432 GetInvalidationService()); 433 fake_server_->AddObserver(invalidation_service); 434 if (TestUsesSelfNotifications()) { 435 invalidation_service->EnableSelfNotifications(); 436 } else { 437 invalidation_service->DisableSelfNotifications(); 438 } 439 fake_server_invalidation_services_[index] = invalidation_service; 440 } else { 441 invalidation::P2PInvalidationService* p2p_invalidation_service = 442 static_cast<invalidation::P2PInvalidationService*>( 443 static_cast<invalidation::ProfileInvalidationProvider*>( 444 invalidation::ProfileInvalidationProviderFactory:: 445 GetInstance()->SetTestingFactoryAndUse( 446 GetProfile(index), 447 TestUsesSelfNotifications() ? 448 BuildSelfNotifyingP2PProfileInvalidationProvider : 449 BuildRealisticP2PProfileInvalidationProvider))-> 450 GetInvalidationService()); 451 p2p_invalidation_service->UpdateCredentials(username_, password_); 452 // Start listening for and emitting notifications of commits. 453 invalidation_forwarders_[index] = 454 new P2PInvalidationForwarder(clients_[index]->service(), 455 p2p_invalidation_service); 456 } 457 } 458 459 bool SyncTest::SetupSync() { 460 // Create sync profiles and clients if they haven't already been created. 461 if (profiles_.empty()) { 462 if (!SetupClients()) 463 LOG(FATAL) << "SetupClients() failed."; 464 } 465 466 // Sync each of the profiles. 467 for (int i = 0; i < num_clients_; ++i) { 468 if (!GetClient(i)->SetupSync()) 469 LOG(FATAL) << "SetupSync() failed."; 470 } 471 472 // Because clients may modify sync data as part of startup (for example local 473 // session-releated data is rewritten), we need to ensure all startup-based 474 // changes have propagated between the clients. 475 // 476 // Tests that don't use self-notifications can't await quiescense. They'll 477 // have to find their own way of waiting for an initial state if they really 478 // need such guarantees. 479 if (TestUsesSelfNotifications()) { 480 AwaitQuiescence(); 481 } 482 483 return true; 484 } 485 486 void SyncTest::TearDownOnMainThread() { 487 for (size_t i = 0; i < clients_.size(); ++i) { 488 clients_[i]->service()->DisableForUser(); 489 } 490 491 // Some of the pending messages might rely on browser windows still being 492 // around, so run messages both before and after closing all browsers. 493 content::RunAllPendingInMessageLoop(); 494 // Close all browser windows. 495 chrome::CloseAllBrowsers(); 496 content::RunAllPendingInMessageLoop(); 497 498 if (fake_server_.get()) { 499 std::vector<fake_server::FakeServerInvalidationService*>::const_iterator it; 500 for (it = fake_server_invalidation_services_.begin(); 501 it != fake_server_invalidation_services_.end(); ++it) { 502 fake_server_->RemoveObserver(*it); 503 } 504 } 505 506 // All browsers should be closed at this point, or else we could see memory 507 // corruption in QuitBrowser(). 508 CHECK_EQ(0U, chrome::GetTotalBrowserCount()); 509 invalidation_forwarders_.clear(); 510 fake_server_invalidation_services_.clear(); 511 clients_.clear(); 512 } 513 514 void SyncTest::SetUpInProcessBrowserTestFixture() { 515 // We don't take a reference to |resolver|, but mock_host_resolver_override_ 516 // does, so effectively assumes ownership. 517 net::RuleBasedHostResolverProc* resolver = 518 new net::RuleBasedHostResolverProc(host_resolver()); 519 resolver->AllowDirectLookup("*.google.com"); 520 // On Linux, we use Chromium's NSS implementation which uses the following 521 // hosts for certificate verification. Without these overrides, running the 522 // integration tests on Linux causes error as we make external DNS lookups. 523 resolver->AllowDirectLookup("*.thawte.com"); 524 resolver->AllowDirectLookup("*.geotrust.com"); 525 resolver->AllowDirectLookup("*.gstatic.com"); 526 mock_host_resolver_override_.reset( 527 new net::ScopedDefaultHostResolverProc(resolver)); 528 } 529 530 void SyncTest::TearDownInProcessBrowserTestFixture() { 531 mock_host_resolver_override_.reset(); 532 } 533 534 void SyncTest::ReadPasswordFile() { 535 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 536 password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest); 537 if (password_file_.empty()) 538 LOG(FATAL) << "Can't run live server test without specifying --" 539 << switches::kPasswordFileForTest << "=<filename>"; 540 std::string file_contents; 541 base::ReadFileToString(password_file_, &file_contents); 542 ASSERT_NE(file_contents, "") << "Password file \"" 543 << password_file_.value() << "\" does not exist."; 544 std::vector<std::string> tokens; 545 std::string delimiters = "\r\n"; 546 Tokenize(file_contents, delimiters, &tokens); 547 ASSERT_EQ(2U, tokens.size()) << "Password file \"" 548 << password_file_.value() 549 << "\" must contain exactly two lines of text."; 550 username_ = tokens[0]; 551 password_ = tokens[1]; 552 } 553 554 void SyncTest::SetupMockGaiaResponses() { 555 factory_.reset(new net::URLFetcherImplFactory()); 556 fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get())); 557 fake_factory_->SetFakeResponse( 558 GaiaUrls::GetInstance()->get_user_info_url(), 559 "email=user (at) gmail.com\ndisplayEmail=user (at) gmail.com", 560 net::HTTP_OK, 561 net::URLRequestStatus::SUCCESS); 562 fake_factory_->SetFakeResponse( 563 GaiaUrls::GetInstance()->issue_auth_token_url(), 564 "auth", 565 net::HTTP_OK, 566 net::URLRequestStatus::SUCCESS); 567 fake_factory_->SetFakeResponse( 568 GURL(GoogleURLTracker::kSearchDomainCheckURL), 569 ".google.com", 570 net::HTTP_OK, 571 net::URLRequestStatus::SUCCESS); 572 fake_factory_->SetFakeResponse( 573 GaiaUrls::GetInstance()->client_login_to_oauth2_url(), 574 "some_response", 575 net::HTTP_OK, 576 net::URLRequestStatus::SUCCESS); 577 fake_factory_->SetFakeResponse( 578 GaiaUrls::GetInstance()->oauth2_token_url(), 579 "{" 580 " \"refresh_token\": \"rt1\"," 581 " \"access_token\": \"at1\"," 582 " \"expires_in\": 3600," 583 " \"token_type\": \"Bearer\"" 584 "}", 585 net::HTTP_OK, 586 net::URLRequestStatus::SUCCESS); 587 fake_factory_->SetFakeResponse( 588 GaiaUrls::GetInstance()->oauth_user_info_url(), 589 "{" 590 " \"id\": \"12345\"" 591 "}", 592 net::HTTP_OK, 593 net::URLRequestStatus::SUCCESS); 594 fake_factory_->SetFakeResponse( 595 GaiaUrls::GetInstance()->oauth1_login_url(), 596 "SID=sid\nLSID=lsid\nAuth=auth_token", 597 net::HTTP_OK, 598 net::URLRequestStatus::SUCCESS); 599 fake_factory_->SetFakeResponse( 600 GaiaUrls::GetInstance()->oauth2_revoke_url(), 601 "", 602 net::HTTP_OK, 603 net::URLRequestStatus::SUCCESS); 604 } 605 606 void SyncTest::SetOAuth2TokenResponse(const std::string& response_data, 607 net::HttpStatusCode response_code, 608 net::URLRequestStatus::Status status) { 609 ASSERT_TRUE(NULL != fake_factory_.get()); 610 fake_factory_->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(), 611 response_data, response_code, status); 612 } 613 614 void SyncTest::ClearMockGaiaResponses() { 615 // Clear any mock gaia responses that might have been set. 616 if (fake_factory_) { 617 fake_factory_->ClearFakeResponses(); 618 fake_factory_.reset(); 619 } 620 621 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we 622 // created. 623 net::URLFetcher::CancelAll(); 624 factory_.reset(); 625 } 626 627 void SyncTest::DecideServerType() { 628 // Only set |server_type_| if it hasn't already been set. This allows for 629 // tests to explicitly set this value in each test class if needed. 630 if (server_type_ == SERVER_TYPE_UNDECIDED) { 631 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 632 if (!cl->HasSwitch(switches::kSyncServiceURL) && 633 !cl->HasSwitch(switches::kSyncServerCommandLine)) { 634 // If neither a sync server URL nor a sync server command line is 635 // provided, start up a local sync test server and point Chrome 636 // to its URL. This is the most common configuration, and the only 637 // one that makes sense for most developers. FakeServer is the 638 // current solution but some scenarios are only supported by the 639 // legacy python server. 640 switch (test_type_) { 641 case SINGLE_CLIENT: 642 case TWO_CLIENT: 643 case MULTIPLE_CLIENT: 644 server_type_ = IN_PROCESS_FAKE_SERVER; 645 break; 646 default: 647 server_type_ = LOCAL_PYTHON_SERVER; 648 } 649 } else if (cl->HasSwitch(switches::kSyncServiceURL) && 650 cl->HasSwitch(switches::kSyncServerCommandLine)) { 651 // If a sync server URL and a sync server command line are provided, 652 // start up a local sync server by running the command line. Chrome 653 // will connect to the server at the URL that was provided. 654 server_type_ = LOCAL_LIVE_SERVER; 655 } else if (cl->HasSwitch(switches::kSyncServiceURL) && 656 !cl->HasSwitch(switches::kSyncServerCommandLine)) { 657 // If a sync server URL is provided, but not a server command line, 658 // it is assumed that the server is already running. Chrome will 659 // automatically connect to it at the URL provided. There is nothing 660 // to do here. 661 server_type_ = EXTERNAL_LIVE_SERVER; 662 } else { 663 // If a sync server command line is provided, but not a server URL, 664 // we flag an error. 665 LOG(FATAL) << "Can't figure out how to run a server."; 666 } 667 } 668 } 669 670 // Start up a local sync server based on the value of server_type_, which 671 // was determined from the command line parameters. 672 void SyncTest::SetUpTestServerIfRequired() { 673 if (server_type_ == LOCAL_PYTHON_SERVER) { 674 if (!SetUpLocalPythonTestServer()) 675 LOG(FATAL) << "Failed to set up local python sync and XMPP servers"; 676 SetupMockGaiaResponses(); 677 } else if (server_type_ == LOCAL_LIVE_SERVER) { 678 // Using mock gaia credentials requires the use of a mock XMPP server. 679 if (username_ == "user (at) gmail.com" && !SetUpLocalPythonTestServer()) 680 LOG(FATAL) << "Failed to set up local python XMPP server"; 681 if (!SetUpLocalTestServer()) 682 LOG(FATAL) << "Failed to set up local test server"; 683 } else if (server_type_ == IN_PROCESS_FAKE_SERVER) { 684 fake_server_.reset(new fake_server::FakeServer()); 685 SetupMockGaiaResponses(); 686 } else if (server_type_ == EXTERNAL_LIVE_SERVER) { 687 // Nothing to do; we'll just talk to the URL we were given. 688 } else { 689 LOG(FATAL) << "Don't know which server environment to run test in."; 690 } 691 } 692 693 bool SyncTest::SetUpLocalPythonTestServer() { 694 EXPECT_TRUE(sync_server_.Start()) 695 << "Could not launch local python test server."; 696 697 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 698 if (server_type_ == LOCAL_PYTHON_SERVER) { 699 std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec(); 700 cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url); 701 DVLOG(1) << "Started local python sync server at " << sync_service_url; 702 } 703 704 int xmpp_port = 0; 705 if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) { 706 LOG(ERROR) << "Could not find valid xmpp_port value"; 707 return false; 708 } 709 if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) { 710 LOG(ERROR) << "Invalid xmpp port: " << xmpp_port; 711 return false; 712 } 713 714 net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair()); 715 xmpp_host_port_pair.set_port(xmpp_port); 716 xmpp_port_.reset(new net::ScopedPortException(xmpp_port)); 717 718 if (!cl->HasSwitch(invalidation::switches::kSyncNotificationHostPort)) { 719 cl->AppendSwitchASCII(invalidation::switches::kSyncNotificationHostPort, 720 xmpp_host_port_pair.ToString()); 721 // The local XMPP server only supports insecure connections. 722 cl->AppendSwitch(invalidation::switches::kSyncAllowInsecureXmppConnection); 723 } 724 DVLOG(1) << "Started local python XMPP server at " 725 << xmpp_host_port_pair.ToString(); 726 727 return true; 728 } 729 730 bool SyncTest::SetUpLocalTestServer() { 731 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 732 base::CommandLine::StringType server_cmdline_string = 733 cl->GetSwitchValueNative(switches::kSyncServerCommandLine); 734 base::CommandLine::StringVector server_cmdline_vector; 735 base::CommandLine::StringType delimiters(FILE_PATH_LITERAL(" ")); 736 Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector); 737 base::CommandLine server_cmdline(server_cmdline_vector); 738 base::LaunchOptions options; 739 #if defined(OS_WIN) 740 options.start_hidden = true; 741 #endif 742 if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_)) 743 LOG(ERROR) << "Could not launch local test server."; 744 745 const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout(); 746 const int kNumIntervals = 15; 747 if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) { 748 DVLOG(1) << "Started local test server at " 749 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; 750 return true; 751 } else { 752 LOG(ERROR) << "Could not start local test server at " 753 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; 754 return false; 755 } 756 } 757 758 bool SyncTest::TearDownLocalPythonTestServer() { 759 if (!sync_server_.Stop()) { 760 LOG(ERROR) << "Could not stop local python test server."; 761 return false; 762 } 763 xmpp_port_.reset(); 764 return true; 765 } 766 767 bool SyncTest::TearDownLocalTestServer() { 768 if (test_server_handle_ != base::kNullProcessHandle) { 769 EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false)) 770 << "Could not stop local test server."; 771 base::CloseProcessHandle(test_server_handle_); 772 test_server_handle_ = base::kNullProcessHandle; 773 } 774 return true; 775 } 776 777 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) { 778 for (int i = 0; i < intervals; ++i) { 779 if (IsTestServerRunning()) 780 return true; 781 base::PlatformThread::Sleep(wait / intervals); 782 } 783 return false; 784 } 785 786 bool SyncTest::IsTestServerRunning() { 787 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 788 std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL); 789 GURL sync_url_status(sync_url.append("/healthz")); 790 SyncServerStatusChecker delegate; 791 scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create( 792 sync_url_status, net::URLFetcher::GET, &delegate)); 793 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | 794 net::LOAD_DO_NOT_SEND_COOKIES | 795 net::LOAD_DO_NOT_SAVE_COOKIES); 796 fetcher->SetRequestContext(g_browser_process->system_request_context()); 797 fetcher->Start(); 798 content::RunMessageLoop(); 799 return delegate.running(); 800 } 801 802 void SyncTest::EnableNetwork(Profile* profile) { 803 // TODO(pvalenzuela): Remove this restriction when FakeServer's observers 804 // (namely FakeServerInvaldationService) are aware of a network disconnect. 805 ASSERT_NE(IN_PROCESS_FAKE_SERVER, server_type_) 806 << "FakeServer does not support EnableNetwork."; 807 SetProxyConfig(profile->GetRequestContext(), 808 net::ProxyConfig::CreateDirect()); 809 if (notifications_enabled_) { 810 EnableNotificationsImpl(); 811 } 812 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. 813 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 814 } 815 816 void SyncTest::DisableNetwork(Profile* profile) { 817 // TODO(pvalenzuela): Remove this restriction when FakeServer's observers 818 // (namely FakeServerInvaldationService) are aware of a network disconnect. 819 ASSERT_NE(IN_PROCESS_FAKE_SERVER, server_type_) 820 << "FakeServer does not support DisableNetwork."; 821 DisableNotificationsImpl(); 822 // Set the current proxy configuration to a nonexistent proxy to effectively 823 // disable networking. 824 net::ProxyConfig config; 825 config.proxy_rules().ParseFromString("http=127.0.0.1:0"); 826 SetProxyConfig(profile->GetRequestContext(), config); 827 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. 828 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 829 } 830 831 bool SyncTest::TestUsesSelfNotifications() { 832 return true; 833 } 834 835 bool SyncTest::EnableEncryption(int index) { 836 ProfileSyncService* service = GetClient(index)->service(); 837 838 if (::IsEncryptionComplete(service)) 839 return true; 840 841 service->EnableEncryptEverything(); 842 843 // In order to kick off the encryption we have to reconfigure. Just grab the 844 // currently synced types and use them. 845 const syncer::ModelTypeSet synced_datatypes = 846 service->GetPreferredDataTypes(); 847 bool sync_everything = synced_datatypes.Equals(syncer::ModelTypeSet::All()); 848 service->OnUserChoseDatatypes(sync_everything, synced_datatypes); 849 850 return AwaitEncryptionComplete(index); 851 } 852 853 bool SyncTest::IsEncryptionComplete(int index) { 854 return ::IsEncryptionComplete(GetClient(index)->service()); 855 } 856 857 bool SyncTest::AwaitEncryptionComplete(int index) { 858 ProfileSyncService* service = GetClient(index)->service(); 859 EncryptionChecker checker(service); 860 checker.Wait(); 861 return !checker.TimedOut(); 862 } 863 864 bool SyncTest::AwaitQuiescence() { 865 return ProfileSyncServiceHarness::AwaitQuiescence(clients()); 866 } 867 868 bool SyncTest::ServerSupportsNotificationControl() const { 869 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); 870 871 // Supported only if we're using the python testserver. 872 return server_type_ == LOCAL_PYTHON_SERVER; 873 } 874 875 void SyncTest::DisableNotificationsImpl() { 876 ASSERT_TRUE(ServerSupportsNotificationControl()); 877 std::string path = "chromiumsync/disablenotifications"; 878 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 879 ASSERT_EQ("Notifications disabled", 880 base::UTF16ToASCII( 881 browser()->tab_strip_model()->GetActiveWebContents()-> 882 GetTitle())); 883 } 884 885 void SyncTest::DisableNotifications() { 886 DisableNotificationsImpl(); 887 notifications_enabled_ = false; 888 } 889 890 void SyncTest::EnableNotificationsImpl() { 891 ASSERT_TRUE(ServerSupportsNotificationControl()); 892 std::string path = "chromiumsync/enablenotifications"; 893 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 894 ASSERT_EQ("Notifications enabled", 895 base::UTF16ToASCII( 896 browser()->tab_strip_model()->GetActiveWebContents()-> 897 GetTitle())); 898 } 899 900 void SyncTest::EnableNotifications() { 901 EnableNotificationsImpl(); 902 notifications_enabled_ = true; 903 } 904 905 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) { 906 ASSERT_TRUE(ServerSupportsNotificationControl()); 907 const std::string& data = 908 syncer::P2PNotificationData( 909 "from_server", 910 syncer::NOTIFY_ALL, 911 syncer::ObjectIdInvalidationMap::InvalidateAll( 912 syncer::ModelTypeSetToObjectIdSet(changed_types))).ToString(); 913 const std::string& path = 914 std::string("chromiumsync/sendnotification?channel=") + 915 syncer::kSyncP2PNotificationChannel + "&data=" + data; 916 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 917 ASSERT_EQ("Notification sent", 918 base::UTF16ToASCII( 919 browser()->tab_strip_model()->GetActiveWebContents()-> 920 GetTitle())); 921 } 922 923 bool SyncTest::ServerSupportsErrorTriggering() const { 924 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); 925 926 // Supported only if we're using the python testserver. 927 return server_type_ == LOCAL_PYTHON_SERVER; 928 } 929 930 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) { 931 ASSERT_TRUE(ServerSupportsErrorTriggering()); 932 std::string path = "chromiumsync/migrate"; 933 char joiner = '?'; 934 for (syncer::ModelTypeSet::Iterator it = model_types.First(); 935 it.Good(); it.Inc()) { 936 path.append( 937 base::StringPrintf( 938 "%ctype=%d", joiner, 939 syncer::GetSpecificsFieldNumberFromModelType(it.Get()))); 940 joiner = '&'; 941 } 942 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 943 ASSERT_EQ("Migration: 200", 944 base::UTF16ToASCII( 945 browser()->tab_strip_model()->GetActiveWebContents()-> 946 GetTitle())); 947 } 948 949 void SyncTest::TriggerTransientError() { 950 ASSERT_TRUE(ServerSupportsErrorTriggering()); 951 std::string path = "chromiumsync/transienterror"; 952 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 953 ASSERT_EQ("Transient error", 954 base::UTF16ToASCII( 955 browser()->tab_strip_model()->GetActiveWebContents()-> 956 GetTitle())); 957 } 958 959 void SyncTest::TriggerXmppAuthError() { 960 ASSERT_TRUE(ServerSupportsErrorTriggering()); 961 std::string path = "chromiumsync/xmppcred"; 962 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 963 } 964 965 namespace { 966 967 sync_pb::SyncEnums::ErrorType 968 GetClientToServerResponseErrorType( 969 syncer::SyncProtocolErrorType error) { 970 switch (error) { 971 case syncer::SYNC_SUCCESS: 972 return sync_pb::SyncEnums::SUCCESS; 973 case syncer::NOT_MY_BIRTHDAY: 974 return sync_pb::SyncEnums::NOT_MY_BIRTHDAY; 975 case syncer::THROTTLED: 976 return sync_pb::SyncEnums::THROTTLED; 977 case syncer::CLEAR_PENDING: 978 return sync_pb::SyncEnums::CLEAR_PENDING; 979 case syncer::TRANSIENT_ERROR: 980 return sync_pb::SyncEnums::TRANSIENT_ERROR; 981 case syncer::MIGRATION_DONE: 982 return sync_pb::SyncEnums::MIGRATION_DONE; 983 case syncer::UNKNOWN_ERROR: 984 return sync_pb::SyncEnums::UNKNOWN; 985 case syncer::INVALID_CREDENTIAL: 986 NOTREACHED(); // NOTREACHED() because auth error is not set through 987 // error code in sync response. 988 return sync_pb::SyncEnums::UNKNOWN; 989 case syncer::DISABLED_BY_ADMIN: 990 return sync_pb::SyncEnums::DISABLED_BY_ADMIN; 991 case syncer::USER_ROLLBACK: 992 return sync_pb::SyncEnums::USER_ROLLBACK; 993 case syncer::NON_RETRIABLE_ERROR: 994 return sync_pb::SyncEnums::UNKNOWN; 995 } 996 return sync_pb::SyncEnums::UNKNOWN; 997 } 998 999 sync_pb::SyncEnums::Action GetClientToServerResponseAction( 1000 const syncer::ClientAction& action) { 1001 switch (action) { 1002 case syncer::UPGRADE_CLIENT: 1003 return sync_pb::SyncEnums::UPGRADE_CLIENT; 1004 case syncer::CLEAR_USER_DATA_AND_RESYNC: 1005 return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC; 1006 case syncer::ENABLE_SYNC_ON_ACCOUNT: 1007 return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT; 1008 case syncer::STOP_AND_RESTART_SYNC: 1009 return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC; 1010 case syncer::DISABLE_SYNC_ON_CLIENT: 1011 return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT; 1012 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT: 1013 case syncer::DISABLE_SYNC_AND_ROLLBACK: 1014 case syncer::ROLLBACK_DONE: 1015 NOTREACHED(); // No corresponding proto action for these. Shouldn't 1016 // test. 1017 return sync_pb::SyncEnums::UNKNOWN_ACTION; 1018 case syncer::UNKNOWN_ACTION: 1019 return sync_pb::SyncEnums::UNKNOWN_ACTION; 1020 } 1021 return sync_pb::SyncEnums::UNKNOWN_ACTION; 1022 } 1023 1024 } // namespace 1025 1026 void SyncTest::TriggerSyncError(const syncer::SyncProtocolError& error, 1027 SyncErrorFrequency frequency) { 1028 ASSERT_TRUE(ServerSupportsErrorTriggering()); 1029 std::string path = "chromiumsync/error"; 1030 int error_type = 1031 static_cast<int>(GetClientToServerResponseErrorType( 1032 error.error_type)); 1033 int action = static_cast<int>(GetClientToServerResponseAction( 1034 error.action)); 1035 1036 path.append(base::StringPrintf("?error=%d", error_type)); 1037 path.append(base::StringPrintf("&action=%d", action)); 1038 1039 path.append(base::StringPrintf("&error_description=%s", 1040 error.error_description.c_str())); 1041 path.append(base::StringPrintf("&url=%s", error.url.c_str())); 1042 path.append(base::StringPrintf("&frequency=%d", frequency)); 1043 1044 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 1045 std::string output = base::UTF16ToASCII( 1046 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 1047 ASSERT_TRUE(output.find("SetError: 200") != base::string16::npos); 1048 } 1049 1050 void SyncTest::TriggerCreateSyncedBookmarks() { 1051 ASSERT_TRUE(ServerSupportsErrorTriggering()); 1052 std::string path = "chromiumsync/createsyncedbookmarks"; 1053 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 1054 ASSERT_EQ("Synced Bookmarks", 1055 base::UTF16ToASCII( 1056 browser()->tab_strip_model()->GetActiveWebContents()-> 1057 GetTitle())); 1058 } 1059 1060 void SyncTest::SetupNetwork(net::URLRequestContextGetter* context_getter) { 1061 base::WaitableEvent done(false, false); 1062 BrowserThread::PostTask( 1063 BrowserThread::IO, FROM_HERE, 1064 base::Bind(&SetupNetworkCallback, &done, 1065 make_scoped_refptr(context_getter))); 1066 done.Wait(); 1067 } 1068 1069 void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter, 1070 const net::ProxyConfig& proxy_config) { 1071 base::WaitableEvent done(false, false); 1072 BrowserThread::PostTask( 1073 BrowserThread::IO, FROM_HERE, 1074 base::Bind(&SetProxyConfigCallback, &done, 1075 make_scoped_refptr(context_getter), proxy_config)); 1076 done.Wait(); 1077 } 1078 1079 fake_server::FakeServer* SyncTest::GetFakeServer() const { 1080 return fake_server_.get(); 1081 } 1082