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