sync_test.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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/message_loop/message_loop.h" 13#include "base/path_service.h" 14#include "base/strings/string_util.h" 15#include "base/strings/stringprintf.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/synchronization/waitable_event.h" 18#include "base/test/test_timeouts.h" 19#include "base/threading/platform_thread.h" 20#include "base/values.h" 21#include "chrome/browser/bookmarks/bookmark_model_factory.h" 22#include "chrome/browser/google/google_url_tracker.h" 23#include "chrome/browser/history/history_service_factory.h" 24#include "chrome/browser/invalidation/invalidation_service_factory.h" 25#include "chrome/browser/invalidation/p2p_invalidation_service.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.h" 30#include "chrome/browser/search_engines/template_url_service_factory.h" 31#include "chrome/browser/sync/profile_sync_service_factory.h" 32#include "chrome/browser/sync/profile_sync_service_harness.h" 33#include "chrome/browser/sync/test/integration/sync_datatype_helper.h" 34#include "chrome/browser/ui/browser.h" 35#include "chrome/browser/ui/browser_finder.h" 36#include "chrome/browser/ui/host_desktop.h" 37#include "chrome/browser/ui/tabs/tab_strip_model.h" 38#include "chrome/common/chrome_paths.h" 39#include "chrome/common/chrome_switches.h" 40#include "chrome/test/base/testing_browser_process.h" 41#include "chrome/test/base/ui_test_utils.h" 42#include "components/webdata/encryptor/encryptor.h" 43#include "content/public/browser/web_contents.h" 44#include "content/public/test/test_browser_thread.h" 45#include "google_apis/gaia/gaia_urls.h" 46#include "net/base/escape.h" 47#include "net/base/load_flags.h" 48#include "net/base/network_change_notifier.h" 49#include "net/proxy/proxy_config.h" 50#include "net/proxy/proxy_config_service_fixed.h" 51#include "net/proxy/proxy_service.h" 52#include "net/test/spawned_test_server/spawned_test_server.h" 53#include "net/url_request/test_url_fetcher_factory.h" 54#include "net/url_request/url_fetcher.h" 55#include "net/url_request/url_fetcher_delegate.h" 56#include "net/url_request/url_request_context.h" 57#include "net/url_request/url_request_context_getter.h" 58#include "net/url_request/url_request_status.h" 59#include "sync/engine/sync_scheduler_impl.h" 60#include "sync/notifier/p2p_invalidator.h" 61#include "sync/protocol/sync.pb.h" 62#include "url/gurl.h" 63 64using content::BrowserThread; 65using invalidation::InvalidationServiceFactory; 66 67namespace switches { 68const char kPasswordFileForTest[] = "password-file-for-test"; 69const char kSyncUserForTest[] = "sync-user-for-test"; 70const char kSyncPasswordForTest[] = "sync-password-for-test"; 71const char kSyncServerCommandLine[] = "sync-server-command-line"; 72} 73 74// Helper class that checks whether a sync test server is running or not. 75class SyncServerStatusChecker : public net::URLFetcherDelegate { 76 public: 77 SyncServerStatusChecker() : running_(false) {} 78 79 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { 80 std::string data; 81 source->GetResponseAsString(&data); 82 running_ = 83 (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && 84 source->GetResponseCode() == 200 && data.find("ok") == 0); 85 base::MessageLoop::current()->Quit(); 86 } 87 88 bool running() const { return running_; } 89 90 private: 91 bool running_; 92}; 93 94void SetProxyConfigCallback( 95 base::WaitableEvent* done, 96 net::URLRequestContextGetter* url_request_context_getter, 97 const net::ProxyConfig& proxy_config) { 98 net::ProxyService* proxy_service = 99 url_request_context_getter->GetURLRequestContext()->proxy_service(); 100 proxy_service->ResetConfigService( 101 new net::ProxyConfigServiceFixed(proxy_config)); 102 done->Signal(); 103} 104 105SyncTest::SyncTest(TestType test_type) 106 : test_type_(test_type), 107 server_type_(SERVER_TYPE_UNDECIDED), 108 num_clients_(-1), 109 use_verifier_(true), 110 notifications_enabled_(true), 111 test_server_handle_(base::kNullProcessHandle), 112 number_of_default_sync_items_(0) { 113 sync_datatype_helper::AssociateWithTest(this); 114 switch (test_type_) { 115 case SINGLE_CLIENT: { 116 num_clients_ = 1; 117 break; 118 } 119 case TWO_CLIENT: { 120 num_clients_ = 2; 121 break; 122 } 123 case MULTIPLE_CLIENT: { 124 num_clients_ = 3; 125 break; 126 } 127 } 128} 129 130SyncTest::~SyncTest() {} 131 132void SyncTest::SetUp() { 133 CommandLine* cl = CommandLine::ForCurrentProcess(); 134 if (cl->HasSwitch(switches::kPasswordFileForTest)) { 135 ReadPasswordFile(); 136 } else if (cl->HasSwitch(switches::kSyncUserForTest) && 137 cl->HasSwitch(switches::kSyncPasswordForTest)) { 138 username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest); 139 password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest); 140 } else { 141 SetupMockGaiaResponses(); 142 } 143 144 if (!cl->HasSwitch(switches::kSyncServiceURL) && 145 !cl->HasSwitch(switches::kSyncServerCommandLine)) { 146 // If neither a sync server URL nor a sync server command line is 147 // provided, start up a local python sync test server and point Chrome 148 // to its URL. This is the most common configuration, and the only 149 // one that makes sense for most developers. 150 server_type_ = LOCAL_PYTHON_SERVER; 151 } else if (cl->HasSwitch(switches::kSyncServiceURL) && 152 cl->HasSwitch(switches::kSyncServerCommandLine)) { 153 // If a sync server URL and a sync server command line are provided, 154 // start up a local sync server by running the command line. Chrome 155 // will connect to the server at the URL that was provided. 156 server_type_ = LOCAL_LIVE_SERVER; 157 } else if (cl->HasSwitch(switches::kSyncServiceURL) && 158 !cl->HasSwitch(switches::kSyncServerCommandLine)) { 159 // If a sync server URL is provided, but not a server command line, 160 // it is assumed that the server is already running. Chrome will 161 // automatically connect to it at the URL provided. There is nothing 162 // to do here. 163 server_type_ = EXTERNAL_LIVE_SERVER; 164 } else { 165 // If a sync server command line is provided, but not a server URL, 166 // we flag an error. 167 LOG(FATAL) << "Can't figure out how to run a server."; 168 } 169 170 if (username_.empty() || password_.empty()) 171 LOG(FATAL) << "Cannot run sync tests without GAIA credentials."; 172 173 // Mock the Mac Keychain service. The real Keychain can block on user input. 174#if defined(OS_MACOSX) 175 Encryptor::UseMockKeychain(true); 176#endif 177 178 // Yield control back to the InProcessBrowserTest framework. 179 InProcessBrowserTest::SetUp(); 180} 181 182void SyncTest::TearDown() { 183 // Clear any mock gaia responses that might have been set. 184 ClearMockGaiaResponses(); 185 186 // Allow the InProcessBrowserTest framework to perform its tear down. 187 InProcessBrowserTest::TearDown(); 188 189 // Stop the local python test server. This is a no-op if one wasn't started. 190 TearDownLocalPythonTestServer(); 191 192 // Stop the local sync test server. This is a no-op if one wasn't started. 193 TearDownLocalTestServer(); 194} 195 196void SyncTest::SetUpCommandLine(CommandLine* cl) { 197 AddTestSwitches(cl); 198 AddOptionalTypesToCommandLine(cl); 199} 200 201void SyncTest::AddTestSwitches(CommandLine* cl) { 202 // Disable non-essential access of external network resources. 203 if (!cl->HasSwitch(switches::kDisableBackgroundNetworking)) 204 cl->AppendSwitch(switches::kDisableBackgroundNetworking); 205 206 if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) 207 cl->AppendSwitch(switches::kSyncShortInitialRetryOverride); 208 209 // TODO(sync): Fix enable_disable_test.cc to play nice with priority 210 // preferences. 211 if (!cl->HasSwitch(switches::kDisableSyncPriorityPreferences)) 212 cl->AppendSwitch(switches::kDisableSyncPriorityPreferences); 213} 214 215void SyncTest::AddOptionalTypesToCommandLine(CommandLine* cl) {} 216 217// static 218Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) { 219 base::FilePath path; 220 PathService::Get(chrome::DIR_USER_DATA, &path); 221 path = path.Append(name); 222 223 if (!base::PathExists(path)) 224 CHECK(file_util::CreateDirectory(path)); 225 226 Profile* profile = 227 Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS); 228 g_browser_process->profile_manager()->RegisterTestingProfile(profile, 229 true, 230 true); 231 return profile; 232} 233 234Profile* SyncTest::GetProfile(int index) { 235 if (profiles_.empty()) 236 LOG(FATAL) << "SetupClients() has not yet been called."; 237 if (index < 0 || index >= static_cast<int>(profiles_.size())) 238 LOG(FATAL) << "GetProfile(): Index is out of bounds."; 239 return profiles_[index]; 240} 241 242Browser* SyncTest::GetBrowser(int index) { 243 if (browsers_.empty()) 244 LOG(FATAL) << "SetupClients() has not yet been called."; 245 if (index < 0 || index >= static_cast<int>(browsers_.size())) 246 LOG(FATAL) << "GetBrowser(): Index is out of bounds."; 247 return browsers_[index]; 248} 249 250ProfileSyncServiceHarness* SyncTest::GetClient(int index) { 251 if (clients_.empty()) 252 LOG(FATAL) << "SetupClients() has not yet been called."; 253 if (index < 0 || index >= static_cast<int>(clients_.size())) 254 LOG(FATAL) << "GetClient(): Index is out of bounds."; 255 return clients_[index]; 256} 257 258Profile* SyncTest::verifier() { 259 if (verifier_ == NULL) 260 LOG(FATAL) << "SetupClients() has not yet been called."; 261 return verifier_; 262} 263 264void SyncTest::DisableVerifier() { 265 use_verifier_ = false; 266} 267 268bool SyncTest::SetupClients() { 269 if (num_clients_ <= 0) 270 LOG(FATAL) << "num_clients_ incorrectly initialized."; 271 if (!profiles_.empty() || !browsers_.empty() || !clients_.empty()) 272 LOG(FATAL) << "SetupClients() has already been called."; 273 274 // Start up a sync test server if one is needed. 275 SetUpTestServerIfRequired(); 276 277 // Create the required number of sync profiles, browsers and clients. 278 profiles_.resize(num_clients_); 279 browsers_.resize(num_clients_); 280 clients_.resize(num_clients_); 281 for (int i = 0; i < num_clients_; ++i) { 282 InitializeInstance(i); 283 } 284 285 // Create the verifier profile. 286 verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier")); 287 ui_test_utils::WaitForBookmarkModelToLoad( 288 BookmarkModelFactory::GetForProfile(verifier())); 289 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 290 verifier(), Profile::EXPLICIT_ACCESS)); 291 ui_test_utils::WaitForTemplateURLServiceToLoad( 292 TemplateURLServiceFactory::GetForProfile(verifier())); 293 return (verifier_ != NULL); 294} 295 296void SyncTest::InitializeInstance(int index) { 297 profiles_[index] = MakeProfile( 298 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index)); 299 EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile " 300 << index << "."; 301 302 browsers_[index] = new Browser(Browser::CreateParams( 303 GetProfile(index), chrome::GetActiveDesktop())); 304 EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser " 305 << index << "."; 306 307 invalidation::P2PInvalidationService* p2p_invalidation_service = 308 InvalidationServiceFactory::GetInstance()-> 309 BuildAndUseP2PInvalidationServiceForTest(GetProfile(index)); 310 p2p_invalidation_service->UpdateCredentials(username_, password_); 311 312 // Make sure the ProfileSyncService has been created before creating the 313 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to 314 // already exist. 315 ProfileSyncServiceFactory::GetForProfile(GetProfile(index)); 316 317 clients_[index] = 318 ProfileSyncServiceHarness::CreateForIntegrationTest( 319 GetProfile(index), 320 username_, 321 password_, 322 p2p_invalidation_service); 323 EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client " 324 << index << "."; 325 326 ui_test_utils::WaitForBookmarkModelToLoad( 327 BookmarkModelFactory::GetForProfile(GetProfile(index))); 328 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 329 GetProfile(index), Profile::EXPLICIT_ACCESS)); 330 ui_test_utils::WaitForTemplateURLServiceToLoad( 331 TemplateURLServiceFactory::GetForProfile(GetProfile(index))); 332} 333 334bool SyncTest::SetupSync() { 335 // Create sync profiles and clients if they haven't already been created. 336 if (profiles_.empty()) { 337 if (!SetupClients()) 338 LOG(FATAL) << "SetupClients() failed."; 339 } 340 341 // Sync each of the profiles. 342 for (int i = 0; i < num_clients_; ++i) { 343 if (!GetClient(i)->SetupSync()) 344 LOG(FATAL) << "SetupSync() failed."; 345 } 346 347 // Because clients may modify sync data as part of startup (for example local 348 // session-releated data is rewritten), we need to ensure all startup-based 349 // changes have propagated between the clients. 350 AwaitQuiescence(); 351 352 // The number of default entries is the number of entries existing after 353 // sync startup excluding top level folders and other permanent items. 354 // This value must be updated whenever new permanent items are added (although 355 // this should handle new datatype-specific top level folders). 356 number_of_default_sync_items_ = GetClient(0)->GetNumEntries() - 357 GetClient(0)->GetNumDatatypes() - 6; 358 DVLOG(1) << "Setting " << number_of_default_sync_items_ << " as default " 359 << " number of entries."; 360 361 return true; 362} 363 364void SyncTest::CleanUpOnMainThread() { 365 // Some of the pending messages might rely on browser windows still being 366 // around, so run messages both before and after closing all browsers. 367 content::RunAllPendingInMessageLoop(); 368 // Close all browser windows. 369 chrome::CloseAllBrowsers(); 370 content::RunAllPendingInMessageLoop(); 371 372 // All browsers should be closed at this point, or else we could see memory 373 // corruption in QuitBrowser(). 374 CHECK_EQ(0U, chrome::GetTotalBrowserCount()); 375 clients_.clear(); 376} 377 378void SyncTest::SetUpInProcessBrowserTestFixture() { 379 // We don't take a reference to |resolver|, but mock_host_resolver_override_ 380 // does, so effectively assumes ownership. 381 net::RuleBasedHostResolverProc* resolver = 382 new net::RuleBasedHostResolverProc(host_resolver()); 383 resolver->AllowDirectLookup("*.google.com"); 384 // On Linux, we use Chromium's NSS implementation which uses the following 385 // hosts for certificate verification. Without these overrides, running the 386 // integration tests on Linux causes error as we make external DNS lookups. 387 resolver->AllowDirectLookup("*.thawte.com"); 388 resolver->AllowDirectLookup("*.geotrust.com"); 389 resolver->AllowDirectLookup("*.gstatic.com"); 390 mock_host_resolver_override_.reset( 391 new net::ScopedDefaultHostResolverProc(resolver)); 392} 393 394void SyncTest::TearDownInProcessBrowserTestFixture() { 395 mock_host_resolver_override_.reset(); 396} 397 398void SyncTest::ReadPasswordFile() { 399 CommandLine* cl = CommandLine::ForCurrentProcess(); 400 password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest); 401 if (password_file_.empty()) 402 LOG(FATAL) << "Can't run live server test without specifying --" 403 << switches::kPasswordFileForTest << "=<filename>"; 404 std::string file_contents; 405 file_util::ReadFileToString(password_file_, &file_contents); 406 ASSERT_NE(file_contents, "") << "Password file \"" 407 << password_file_.value() << "\" does not exist."; 408 std::vector<std::string> tokens; 409 std::string delimiters = "\r\n"; 410 Tokenize(file_contents, delimiters, &tokens); 411 ASSERT_EQ(2U, tokens.size()) << "Password file \"" 412 << password_file_.value() 413 << "\" must contain exactly two lines of text."; 414 username_ = tokens[0]; 415 password_ = tokens[1]; 416} 417 418void SyncTest::SetupMockGaiaResponses() { 419 username_ = "user@gmail.com"; 420 password_ = "password"; 421 factory_.reset(new net::URLFetcherImplFactory()); 422 fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get())); 423 fake_factory_->SetFakeResponse( 424 GaiaUrls::GetInstance()->client_login_url(), 425 "SID=sid\nLSID=lsid", 426 true); 427 fake_factory_->SetFakeResponse( 428 GaiaUrls::GetInstance()->get_user_info_url(), 429 "email=user@gmail.com\ndisplayEmail=user@gmail.com", 430 true); 431 fake_factory_->SetFakeResponse( 432 GaiaUrls::GetInstance()->issue_auth_token_url(), 433 "auth", 434 true); 435 fake_factory_->SetFakeResponse( 436 GoogleURLTracker::kSearchDomainCheckURL, 437 ".google.com", 438 true); 439 fake_factory_->SetFakeResponse( 440 GaiaUrls::GetInstance()->client_login_to_oauth2_url(), 441 "some_response", 442 true); 443 fake_factory_->SetFakeResponse( 444 GaiaUrls::GetInstance()->oauth2_token_url(), 445 "{" 446 " \"refresh_token\": \"rt1\"," 447 " \"access_token\": \"at1\"," 448 " \"expires_in\": 3600," 449 " \"token_type\": \"Bearer\"" 450 "}", 451 true); 452 fake_factory_->SetFakeResponse( 453 GaiaUrls::GetInstance()->oauth1_login_url(), 454 "SID=sid\nLSID=lsid\nAuth=auth_token", 455 true); 456} 457 458void SyncTest::ClearMockGaiaResponses() { 459 // Clear any mock gaia responses that might have been set. 460 if (fake_factory_) { 461 fake_factory_->ClearFakeResponses(); 462 fake_factory_.reset(); 463 } 464 465 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we 466 // created. 467 net::URLFetcher::CancelAll(); 468 factory_.reset(); 469} 470 471// Start up a local sync server based on the value of server_type_, which 472// was determined from the command line parameters. 473void SyncTest::SetUpTestServerIfRequired() { 474 if (server_type_ == LOCAL_PYTHON_SERVER) { 475 if (!SetUpLocalPythonTestServer()) 476 LOG(FATAL) << "Failed to set up local python sync and XMPP servers"; 477 } else if (server_type_ == LOCAL_LIVE_SERVER) { 478 // Using mock gaia credentials requires the use of a mock XMPP server. 479 if (username_ == "user@gmail.com" && !SetUpLocalPythonTestServer()) 480 LOG(FATAL) << "Failed to set up local python XMPP server"; 481 if (!SetUpLocalTestServer()) 482 LOG(FATAL) << "Failed to set up local test server"; 483 } else if (server_type_ == EXTERNAL_LIVE_SERVER) { 484 // Nothing to do; we'll just talk to the URL we were given. 485 } else { 486 LOG(FATAL) << "Don't know which server environment to run test in."; 487 } 488} 489 490bool SyncTest::SetUpLocalPythonTestServer() { 491 EXPECT_TRUE(sync_server_.Start()) 492 << "Could not launch local python test server."; 493 494 CommandLine* cl = CommandLine::ForCurrentProcess(); 495 if (server_type_ == LOCAL_PYTHON_SERVER) { 496 std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec(); 497 cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url); 498 DVLOG(1) << "Started local python sync server at " << sync_service_url; 499 } 500 501 int xmpp_port = 0; 502 if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) { 503 LOG(ERROR) << "Could not find valid xmpp_port value"; 504 return false; 505 } 506 if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) { 507 LOG(ERROR) << "Invalid xmpp port: " << xmpp_port; 508 return false; 509 } 510 511 net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair()); 512 xmpp_host_port_pair.set_port(xmpp_port); 513 xmpp_port_.reset(new net::ScopedPortException(xmpp_port)); 514 515 if (!cl->HasSwitch(switches::kSyncNotificationHostPort)) { 516 cl->AppendSwitchASCII(switches::kSyncNotificationHostPort, 517 xmpp_host_port_pair.ToString()); 518 // The local XMPP server only supports insecure connections. 519 cl->AppendSwitch(switches::kSyncAllowInsecureXmppConnection); 520 } 521 DVLOG(1) << "Started local python XMPP server at " 522 << xmpp_host_port_pair.ToString(); 523 524 return true; 525} 526 527bool SyncTest::SetUpLocalTestServer() { 528 CommandLine* cl = CommandLine::ForCurrentProcess(); 529 CommandLine::StringType server_cmdline_string = cl->GetSwitchValueNative( 530 switches::kSyncServerCommandLine); 531 CommandLine::StringVector server_cmdline_vector; 532 CommandLine::StringType delimiters(FILE_PATH_LITERAL(" ")); 533 Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector); 534 CommandLine server_cmdline(server_cmdline_vector); 535 base::LaunchOptions options; 536#if defined(OS_WIN) 537 options.start_hidden = true; 538#endif 539 if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_)) 540 LOG(ERROR) << "Could not launch local test server."; 541 542 const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout(); 543 const int kNumIntervals = 15; 544 if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) { 545 DVLOG(1) << "Started local test server at " 546 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; 547 return true; 548 } else { 549 LOG(ERROR) << "Could not start local test server at " 550 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; 551 return false; 552 } 553} 554 555bool SyncTest::TearDownLocalPythonTestServer() { 556 if (!sync_server_.Stop()) { 557 LOG(ERROR) << "Could not stop local python test server."; 558 return false; 559 } 560 xmpp_port_.reset(); 561 return true; 562} 563 564bool SyncTest::TearDownLocalTestServer() { 565 if (test_server_handle_ != base::kNullProcessHandle) { 566 EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false)) 567 << "Could not stop local test server."; 568 base::CloseProcessHandle(test_server_handle_); 569 test_server_handle_ = base::kNullProcessHandle; 570 } 571 return true; 572} 573 574bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) { 575 for (int i = 0; i < intervals; ++i) { 576 if (IsTestServerRunning()) 577 return true; 578 base::PlatformThread::Sleep(wait / intervals); 579 } 580 return false; 581} 582 583bool SyncTest::IsTestServerRunning() { 584 CommandLine* cl = CommandLine::ForCurrentProcess(); 585 std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL); 586 GURL sync_url_status(sync_url.append("/healthz")); 587 SyncServerStatusChecker delegate; 588 scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create( 589 sync_url_status, net::URLFetcher::GET, &delegate)); 590 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | 591 net::LOAD_DO_NOT_SEND_COOKIES | 592 net::LOAD_DO_NOT_SAVE_COOKIES); 593 fetcher->SetRequestContext(g_browser_process->system_request_context()); 594 fetcher->Start(); 595 content::RunMessageLoop(); 596 return delegate.running(); 597} 598 599void SyncTest::EnableNetwork(Profile* profile) { 600 SetProxyConfig(profile->GetRequestContext(), 601 net::ProxyConfig::CreateDirect()); 602 if (notifications_enabled_) { 603 EnableNotificationsImpl(); 604 } 605 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. 606 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 607} 608 609void SyncTest::DisableNetwork(Profile* profile) { 610 DisableNotificationsImpl(); 611 // Set the current proxy configuration to a nonexistent proxy to effectively 612 // disable networking. 613 net::ProxyConfig config; 614 config.proxy_rules().ParseFromString("http=127.0.0.1:0"); 615 SetProxyConfig(profile->GetRequestContext(), config); 616 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. 617 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 618} 619 620bool SyncTest::EnableEncryption(int index, syncer::ModelType type) { 621 return GetClient(index)->EnableEncryptionForType(type); 622} 623 624bool SyncTest::IsEncrypted(int index, syncer::ModelType type) { 625 return GetClient(index)->IsTypeEncrypted(type); 626} 627 628bool SyncTest::AwaitQuiescence() { 629 return ProfileSyncServiceHarness::AwaitQuiescence(clients()); 630} 631 632bool SyncTest::ServerSupportsNotificationControl() const { 633 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); 634 635 // Supported only if we're using the python testserver. 636 return server_type_ == LOCAL_PYTHON_SERVER; 637} 638 639void SyncTest::DisableNotificationsImpl() { 640 ASSERT_TRUE(ServerSupportsNotificationControl()); 641 std::string path = "chromiumsync/disablenotifications"; 642 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 643 ASSERT_EQ("Notifications disabled", 644 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 645 GetTitle())); 646} 647 648void SyncTest::DisableNotifications() { 649 DisableNotificationsImpl(); 650 notifications_enabled_ = false; 651} 652 653void SyncTest::EnableNotificationsImpl() { 654 ASSERT_TRUE(ServerSupportsNotificationControl()); 655 std::string path = "chromiumsync/enablenotifications"; 656 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 657 ASSERT_EQ("Notifications enabled", 658 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 659 GetTitle())); 660} 661 662void SyncTest::EnableNotifications() { 663 EnableNotificationsImpl(); 664 notifications_enabled_ = true; 665} 666 667void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) { 668 ASSERT_TRUE(ServerSupportsNotificationControl()); 669 const std::string& data = 670 syncer::P2PNotificationData( 671 "from_server", 672 syncer::NOTIFY_ALL, 673 syncer::ObjectIdSetToInvalidationMap( 674 syncer::ModelTypeSetToObjectIdSet(changed_types), 675 syncer::Invalidation::kUnknownVersion, 676 std::string()) 677 ).ToString(); 678 const std::string& path = 679 std::string("chromiumsync/sendnotification?channel=") + 680 syncer::kSyncP2PNotificationChannel + "&data=" + data; 681 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 682 ASSERT_EQ("Notification sent", 683 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 684 GetTitle())); 685} 686 687bool SyncTest::ServerSupportsErrorTriggering() const { 688 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); 689 690 // Supported only if we're using the python testserver. 691 return server_type_ == LOCAL_PYTHON_SERVER; 692} 693 694void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) { 695 ASSERT_TRUE(ServerSupportsErrorTriggering()); 696 std::string path = "chromiumsync/migrate"; 697 char joiner = '?'; 698 for (syncer::ModelTypeSet::Iterator it = model_types.First(); 699 it.Good(); it.Inc()) { 700 path.append( 701 base::StringPrintf( 702 "%ctype=%d", joiner, 703 syncer::GetSpecificsFieldNumberFromModelType(it.Get()))); 704 joiner = '&'; 705 } 706 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 707 ASSERT_EQ("Migration: 200", 708 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 709 GetTitle())); 710} 711 712void SyncTest::TriggerBirthdayError() { 713 ASSERT_TRUE(ServerSupportsErrorTriggering()); 714 std::string path = "chromiumsync/birthdayerror"; 715 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 716 ASSERT_EQ("Birthday error", 717 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 718 GetTitle())); 719} 720 721void SyncTest::TriggerTransientError() { 722 ASSERT_TRUE(ServerSupportsErrorTriggering()); 723 std::string path = "chromiumsync/transienterror"; 724 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 725 ASSERT_EQ("Transient error", 726 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 727 GetTitle())); 728} 729 730void SyncTest::TriggerAuthError() { 731 ASSERT_TRUE(ServerSupportsErrorTriggering()); 732 std::string path = "chromiumsync/cred"; 733 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 734} 735 736void SyncTest::TriggerXmppAuthError() { 737 ASSERT_TRUE(ServerSupportsErrorTriggering()); 738 std::string path = "chromiumsync/xmppcred"; 739 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 740} 741 742namespace { 743 744sync_pb::SyncEnums::ErrorType 745 GetClientToServerResponseErrorType( 746 syncer::SyncProtocolErrorType error) { 747 switch (error) { 748 case syncer::SYNC_SUCCESS: 749 return sync_pb::SyncEnums::SUCCESS; 750 case syncer::NOT_MY_BIRTHDAY: 751 return sync_pb::SyncEnums::NOT_MY_BIRTHDAY; 752 case syncer::THROTTLED: 753 return sync_pb::SyncEnums::THROTTLED; 754 case syncer::CLEAR_PENDING: 755 return sync_pb::SyncEnums::CLEAR_PENDING; 756 case syncer::TRANSIENT_ERROR: 757 return sync_pb::SyncEnums::TRANSIENT_ERROR; 758 case syncer::MIGRATION_DONE: 759 return sync_pb::SyncEnums::MIGRATION_DONE; 760 case syncer::UNKNOWN_ERROR: 761 return sync_pb::SyncEnums::UNKNOWN; 762 default: 763 NOTREACHED(); 764 return sync_pb::SyncEnums::UNKNOWN; 765 } 766} 767 768sync_pb::SyncEnums::Action GetClientToServerResponseAction( 769 const syncer::ClientAction& action) { 770 switch (action) { 771 case syncer::UPGRADE_CLIENT: 772 return sync_pb::SyncEnums::UPGRADE_CLIENT; 773 case syncer::CLEAR_USER_DATA_AND_RESYNC: 774 return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC; 775 case syncer::ENABLE_SYNC_ON_ACCOUNT: 776 return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT; 777 case syncer::STOP_AND_RESTART_SYNC: 778 return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC; 779 case syncer::DISABLE_SYNC_ON_CLIENT: 780 return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT; 781 case syncer::UNKNOWN_ACTION: 782 return sync_pb::SyncEnums::UNKNOWN_ACTION; 783 default: 784 NOTREACHED(); 785 return sync_pb::SyncEnums::UNKNOWN_ACTION; 786 } 787} 788 789} // namespace 790 791void SyncTest::TriggerSyncError(const syncer::SyncProtocolError& error, 792 SyncErrorFrequency frequency) { 793 ASSERT_TRUE(ServerSupportsErrorTriggering()); 794 std::string path = "chromiumsync/error"; 795 int error_type = 796 static_cast<int>(GetClientToServerResponseErrorType( 797 error.error_type)); 798 int action = static_cast<int>(GetClientToServerResponseAction( 799 error.action)); 800 801 path.append(base::StringPrintf("?error=%d", error_type)); 802 path.append(base::StringPrintf("&action=%d", action)); 803 804 path.append(base::StringPrintf("&error_description=%s", 805 error.error_description.c_str())); 806 path.append(base::StringPrintf("&url=%s", error.url.c_str())); 807 path.append(base::StringPrintf("&frequency=%d", frequency)); 808 809 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 810 std::string output = UTF16ToASCII( 811 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 812 ASSERT_TRUE(output.find("SetError: 200") != string16::npos); 813} 814 815void SyncTest::TriggerCreateSyncedBookmarks() { 816 ASSERT_TRUE(ServerSupportsErrorTriggering()); 817 std::string path = "chromiumsync/createsyncedbookmarks"; 818 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); 819 ASSERT_EQ("Synced Bookmarks", 820 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()-> 821 GetTitle())); 822} 823 824int SyncTest::NumberOfDefaultSyncItems() const { 825 return number_of_default_sync_items_; 826} 827 828void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter, 829 const net::ProxyConfig& proxy_config) { 830 base::WaitableEvent done(false, false); 831 BrowserThread::PostTask( 832 BrowserThread::IO, FROM_HERE, 833 base::Bind(&SetProxyConfigCallback, &done, 834 make_scoped_refptr(context_getter), proxy_config)); 835 done.Wait(); 836} 837