Convert most two client sync_integration_tests to use FakeServer
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / sync_test.cc
blob3ae39ce1cbb396dd3ee1e2be030aa4ed62c14fdc
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.
5 #include "chrome/browser/sync/test/integration/sync_test.h"
7 #include <vector>
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/process/launch.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/test/test_timeouts.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/values.h"
22 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
23 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
24 #include "chrome/browser/google/google_url_tracker.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/invalidation/invalidation_service_factory.h"
27 #include "chrome/browser/invalidation/p2p_invalidation_service.h"
28 #include "chrome/browser/invalidation/profile_invalidation_auth_provider.h"
29 #include "chrome/browser/lifetime/application_lifetime.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/profiles/profile_manager.h"
32 #include "chrome/browser/search_engines/template_url_service.h"
33 #include "chrome/browser/search_engines/template_url_service_factory.h"
34 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
35 #include "chrome/browser/signin/signin_manager_factory.h"
36 #include "chrome/browser/sync/profile_sync_service.h"
37 #include "chrome/browser/sync/profile_sync_service_factory.h"
38 #include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h"
39 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
40 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
41 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
42 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
43 #include "chrome/browser/ui/browser.h"
44 #include "chrome/browser/ui/browser_finder.h"
45 #include "chrome/browser/ui/host_desktop.h"
46 #include "chrome/browser/ui/tabs/tab_strip_model.h"
47 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
48 #include "chrome/common/chrome_paths.h"
49 #include "chrome/common/chrome_switches.h"
50 #include "chrome/test/base/testing_browser_process.h"
51 #include "chrome/test/base/ui_test_utils.h"
52 #include "components/os_crypt/os_crypt.h"
53 #include "components/signin/core/browser/signin_manager.h"
54 #include "content/public/browser/web_contents.h"
55 #include "content/public/test/test_browser_thread.h"
56 #include "google_apis/gaia/gaia_urls.h"
57 #include "net/base/escape.h"
58 #include "net/base/load_flags.h"
59 #include "net/base/network_change_notifier.h"
60 #include "net/proxy/proxy_config.h"
61 #include "net/proxy/proxy_config_service_fixed.h"
62 #include "net/proxy/proxy_service.h"
63 #include "net/test/spawned_test_server/spawned_test_server.h"
64 #include "net/url_request/test_url_fetcher_factory.h"
65 #include "net/url_request/url_fetcher.h"
66 #include "net/url_request/url_fetcher_delegate.h"
67 #include "net/url_request/url_request_context.h"
68 #include "net/url_request/url_request_context_getter.h"
69 #include "sync/engine/sync_scheduler_impl.h"
70 #include "sync/notifier/p2p_invalidator.h"
71 #include "sync/protocol/sync.pb.h"
72 #include "sync/test/fake_server/fake_server.h"
73 #include "sync/test/fake_server/fake_server_network_resources.h"
74 #include "url/gurl.h"
76 using content::BrowserThread;
77 using invalidation::InvalidationServiceFactory;
79 namespace switches {
80 const char kPasswordFileForTest[] = "password-file-for-test";
81 const char kSyncUserForTest[] = "sync-user-for-test";
82 const char kSyncPasswordForTest[] = "sync-password-for-test";
83 const char kSyncServerCommandLine[] = "sync-server-command-line";
86 namespace {
88 // Helper class that checks whether a sync test server is running or not.
89 class SyncServerStatusChecker : public net::URLFetcherDelegate {
90 public:
91 SyncServerStatusChecker() : running_(false) {}
93 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
94 std::string data;
95 source->GetResponseAsString(&data);
96 running_ =
97 (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
98 source->GetResponseCode() == 200 && data.find("ok") == 0);
99 base::MessageLoop::current()->Quit();
102 bool running() const { return running_; }
104 private:
105 bool running_;
108 bool IsEncryptionComplete(const ProfileSyncService* service) {
109 return service->EncryptEverythingEnabled() && !service->encryption_pending();
112 // Helper class to wait for encryption to complete.
113 class EncryptionChecker : public SingleClientStatusChangeChecker {
114 public:
115 explicit EncryptionChecker(ProfileSyncService* service)
116 : SingleClientStatusChangeChecker(service) {}
118 virtual bool IsExitConditionSatisfied() OVERRIDE {
119 return IsEncryptionComplete(service());
122 virtual std::string GetDebugMessage() const OVERRIDE {
123 return "Encryption";
127 void SetProxyConfigCallback(
128 base::WaitableEvent* done,
129 net::URLRequestContextGetter* url_request_context_getter,
130 const net::ProxyConfig& proxy_config) {
131 net::ProxyService* proxy_service =
132 url_request_context_getter->GetURLRequestContext()->proxy_service();
133 proxy_service->ResetConfigService(
134 new net::ProxyConfigServiceFixed(proxy_config));
135 done->Signal();
138 KeyedService* BuildP2PInvalidationService(
139 content::BrowserContext* context,
140 syncer::P2PNotificationTarget notification_target) {
141 Profile* profile = static_cast<Profile*>(context);
142 return new invalidation::P2PInvalidationService(
143 profile,
144 scoped_ptr<invalidation::InvalidationAuthProvider>(
145 new invalidation::ProfileInvalidationAuthProvider(
146 SigninManagerFactory::GetForProfile(profile),
147 ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
148 LoginUIServiceFactory::GetForProfile(profile))),
149 notification_target);
152 KeyedService* BuildSelfNotifyingP2PInvalidationService(
153 content::BrowserContext* context) {
154 return BuildP2PInvalidationService(context, syncer::NOTIFY_ALL);
157 KeyedService* BuildRealisticP2PInvalidationService(
158 content::BrowserContext* context) {
159 return BuildP2PInvalidationService(context, syncer::NOTIFY_OTHERS);
162 } // namespace
164 SyncTest::SyncTest(TestType test_type)
165 : test_type_(test_type),
166 server_type_(SERVER_TYPE_UNDECIDED),
167 num_clients_(-1),
168 use_verifier_(true),
169 notifications_enabled_(true),
170 test_server_handle_(base::kNullProcessHandle) {
171 sync_datatype_helper::AssociateWithTest(this);
172 switch (test_type_) {
173 case SINGLE_CLIENT:
174 case SINGLE_CLIENT_LEGACY: {
175 num_clients_ = 1;
176 break;
178 case TWO_CLIENT:
179 case TWO_CLIENT_LEGACY: {
180 num_clients_ = 2;
181 break;
183 case MULTIPLE_CLIENT: {
184 num_clients_ = 3;
185 break;
190 SyncTest::~SyncTest() {}
192 void SyncTest::SetUp() {
193 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
194 if (cl->HasSwitch(switches::kPasswordFileForTest)) {
195 ReadPasswordFile();
196 } else if (cl->HasSwitch(switches::kSyncUserForTest) &&
197 cl->HasSwitch(switches::kSyncPasswordForTest)) {
198 username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest);
199 password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest);
200 } else {
201 username_ = "user@gmail.com";
202 password_ = "password";
205 if (username_.empty() || password_.empty())
206 LOG(FATAL) << "Cannot run sync tests without GAIA credentials.";
208 // Sets |server_type_| if it wasn't specified by the test.
209 DecideServerType();
211 // Mock the Mac Keychain service. The real Keychain can block on user input.
212 #if defined(OS_MACOSX)
213 OSCrypt::UseMockKeychain(true);
214 #endif
216 // Start up a sync test server if one is needed and setup mock gaia responses.
217 // Note: This must be done prior to the call to SetupClients() because we want
218 // the mock gaia responses to be available before GaiaUrls is initialized.
219 SetUpTestServerIfRequired();
221 // Yield control back to the InProcessBrowserTest framework.
222 InProcessBrowserTest::SetUp();
225 void SyncTest::TearDown() {
226 // Clear any mock gaia responses that might have been set.
227 ClearMockGaiaResponses();
229 // Allow the InProcessBrowserTest framework to perform its tear down.
230 InProcessBrowserTest::TearDown();
232 // Stop the local python test server. This is a no-op if one wasn't started.
233 TearDownLocalPythonTestServer();
235 // Stop the local sync test server. This is a no-op if one wasn't started.
236 TearDownLocalTestServer();
239 void SyncTest::SetUpCommandLine(base::CommandLine* cl) {
240 AddTestSwitches(cl);
241 AddOptionalTypesToCommandLine(cl);
244 void SyncTest::AddTestSwitches(base::CommandLine* cl) {
245 // Disable non-essential access of external network resources.
246 if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
247 cl->AppendSwitch(switches::kDisableBackgroundNetworking);
249 if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
250 cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
253 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine* cl) {}
255 // static
256 Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) {
257 base::FilePath path;
258 PathService::Get(chrome::DIR_USER_DATA, &path);
259 path = path.Append(name);
261 if (!base::PathExists(path))
262 CHECK(base::CreateDirectory(path));
264 Profile* profile =
265 Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
266 g_browser_process->profile_manager()->RegisterTestingProfile(profile,
267 true,
268 true);
269 return profile;
272 Profile* SyncTest::GetProfile(int index) {
273 if (profiles_.empty())
274 LOG(FATAL) << "SetupClients() has not yet been called.";
275 if (index < 0 || index >= static_cast<int>(profiles_.size()))
276 LOG(FATAL) << "GetProfile(): Index is out of bounds.";
277 return profiles_[index];
280 Browser* SyncTest::GetBrowser(int index) {
281 if (browsers_.empty())
282 LOG(FATAL) << "SetupClients() has not yet been called.";
283 if (index < 0 || index >= static_cast<int>(browsers_.size()))
284 LOG(FATAL) << "GetBrowser(): Index is out of bounds.";
285 return browsers_[index];
288 ProfileSyncServiceHarness* SyncTest::GetClient(int index) {
289 if (clients_.empty())
290 LOG(FATAL) << "SetupClients() has not yet been called.";
291 if (index < 0 || index >= static_cast<int>(clients_.size()))
292 LOG(FATAL) << "GetClient(): Index is out of bounds.";
293 return clients_[index];
296 ProfileSyncService* SyncTest::GetSyncService(int index) {
297 return ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
300 std::vector<ProfileSyncService*> SyncTest::GetSyncServices() {
301 std::vector<ProfileSyncService*> services;
302 for (int i = 0; i < num_clients(); ++i) {
303 services.push_back(GetSyncService(i));
305 return services;
308 Profile* SyncTest::verifier() {
309 if (verifier_ == NULL)
310 LOG(FATAL) << "SetupClients() has not yet been called.";
311 return verifier_;
314 void SyncTest::DisableVerifier() {
315 use_verifier_ = false;
318 bool SyncTest::SetupClients() {
319 if (num_clients_ <= 0)
320 LOG(FATAL) << "num_clients_ incorrectly initialized.";
321 if (!profiles_.empty() || !browsers_.empty() || !clients_.empty())
322 LOG(FATAL) << "SetupClients() has already been called.";
324 // Create the required number of sync profiles, browsers and clients.
325 profiles_.resize(num_clients_);
326 browsers_.resize(num_clients_);
327 clients_.resize(num_clients_);
328 invalidation_forwarders_.resize(num_clients_);
329 for (int i = 0; i < num_clients_; ++i) {
330 InitializeInstance(i);
333 // Create the verifier profile.
334 verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier"));
335 test::WaitForBookmarkModelToLoad(
336 BookmarkModelFactory::GetForProfile(verifier()));
337 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
338 verifier(), Profile::EXPLICIT_ACCESS));
339 ui_test_utils::WaitForTemplateURLServiceToLoad(
340 TemplateURLServiceFactory::GetForProfile(verifier()));
341 return (verifier_ != NULL);
344 void SyncTest::InitializeInstance(int index) {
345 profiles_[index] = MakeProfile(
346 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index));
347 EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile "
348 << index << ".";
350 browsers_[index] = new Browser(Browser::CreateParams(
351 GetProfile(index), chrome::GetActiveDesktop()));
352 EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser "
353 << index << ".";
355 invalidation::P2PInvalidationService* p2p_invalidation_service =
356 static_cast<invalidation::P2PInvalidationService*>(
357 InvalidationServiceFactory::GetInstance()->SetTestingFactoryAndUse(
358 GetProfile(index),
359 TestUsesSelfNotifications() ?
360 BuildSelfNotifyingP2PInvalidationService
361 : BuildRealisticP2PInvalidationService));
362 p2p_invalidation_service->UpdateCredentials(username_, password_);
364 // Make sure the ProfileSyncService has been created before creating the
365 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
366 // already exist.
367 ProfileSyncService* profile_sync_service =
368 ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
370 if (server_type_ == IN_PROCESS_FAKE_SERVER) {
371 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
372 profile_sync_service->OverrideNetworkResourcesForTest(
373 make_scoped_ptr<syncer::NetworkResources>(
374 new fake_server::FakeServerNetworkResources(fake_server_.get())));
377 clients_[index] =
378 ProfileSyncServiceHarness::Create(
379 GetProfile(index),
380 username_,
381 password_);
382 EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client "
383 << index << ".";
385 // Start listening for and emitting notificaitons of commits.
386 invalidation_forwarders_[index] =
387 new P2PInvalidationForwarder(clients_[index]->service(),
388 p2p_invalidation_service);
390 test::WaitForBookmarkModelToLoad(
391 BookmarkModelFactory::GetForProfile(GetProfile(index)));
392 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
393 GetProfile(index), Profile::EXPLICIT_ACCESS));
394 ui_test_utils::WaitForTemplateURLServiceToLoad(
395 TemplateURLServiceFactory::GetForProfile(GetProfile(index)));
398 bool SyncTest::SetupSync() {
399 // Create sync profiles and clients if they haven't already been created.
400 if (profiles_.empty()) {
401 if (!SetupClients())
402 LOG(FATAL) << "SetupClients() failed.";
405 // Sync each of the profiles.
406 for (int i = 0; i < num_clients_; ++i) {
407 if (!GetClient(i)->SetupSync())
408 LOG(FATAL) << "SetupSync() failed.";
411 // Because clients may modify sync data as part of startup (for example local
412 // session-releated data is rewritten), we need to ensure all startup-based
413 // changes have propagated between the clients.
415 // Tests that don't use self-notifications can't await quiescense. They'll
416 // have to find their own way of waiting for an initial state if they really
417 // need such guarantees.
418 if (TestUsesSelfNotifications()) {
419 AwaitQuiescence();
422 return true;
425 void SyncTest::CleanUpOnMainThread() {
426 for (size_t i = 0; i < clients_.size(); ++i) {
427 clients_[i]->service()->DisableForUser();
430 // Some of the pending messages might rely on browser windows still being
431 // around, so run messages both before and after closing all browsers.
432 content::RunAllPendingInMessageLoop();
433 // Close all browser windows.
434 chrome::CloseAllBrowsers();
435 content::RunAllPendingInMessageLoop();
437 // All browsers should be closed at this point, or else we could see memory
438 // corruption in QuitBrowser().
439 CHECK_EQ(0U, chrome::GetTotalBrowserCount());
440 invalidation_forwarders_.clear();
441 clients_.clear();
444 void SyncTest::SetUpInProcessBrowserTestFixture() {
445 // We don't take a reference to |resolver|, but mock_host_resolver_override_
446 // does, so effectively assumes ownership.
447 net::RuleBasedHostResolverProc* resolver =
448 new net::RuleBasedHostResolverProc(host_resolver());
449 resolver->AllowDirectLookup("*.google.com");
450 // On Linux, we use Chromium's NSS implementation which uses the following
451 // hosts for certificate verification. Without these overrides, running the
452 // integration tests on Linux causes error as we make external DNS lookups.
453 resolver->AllowDirectLookup("*.thawte.com");
454 resolver->AllowDirectLookup("*.geotrust.com");
455 resolver->AllowDirectLookup("*.gstatic.com");
456 mock_host_resolver_override_.reset(
457 new net::ScopedDefaultHostResolverProc(resolver));
460 void SyncTest::TearDownInProcessBrowserTestFixture() {
461 mock_host_resolver_override_.reset();
464 void SyncTest::ReadPasswordFile() {
465 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
466 password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest);
467 if (password_file_.empty())
468 LOG(FATAL) << "Can't run live server test without specifying --"
469 << switches::kPasswordFileForTest << "=<filename>";
470 std::string file_contents;
471 base::ReadFileToString(password_file_, &file_contents);
472 ASSERT_NE(file_contents, "") << "Password file \""
473 << password_file_.value() << "\" does not exist.";
474 std::vector<std::string> tokens;
475 std::string delimiters = "\r\n";
476 Tokenize(file_contents, delimiters, &tokens);
477 ASSERT_EQ(2U, tokens.size()) << "Password file \""
478 << password_file_.value()
479 << "\" must contain exactly two lines of text.";
480 username_ = tokens[0];
481 password_ = tokens[1];
484 void SyncTest::SetupMockGaiaResponses() {
485 factory_.reset(new net::URLFetcherImplFactory());
486 fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
487 fake_factory_->SetFakeResponse(
488 GaiaUrls::GetInstance()->get_user_info_url(),
489 "email=user@gmail.com\ndisplayEmail=user@gmail.com",
490 net::HTTP_OK,
491 net::URLRequestStatus::SUCCESS);
492 fake_factory_->SetFakeResponse(
493 GaiaUrls::GetInstance()->issue_auth_token_url(),
494 "auth",
495 net::HTTP_OK,
496 net::URLRequestStatus::SUCCESS);
497 fake_factory_->SetFakeResponse(
498 GURL(GoogleURLTracker::kSearchDomainCheckURL),
499 ".google.com",
500 net::HTTP_OK,
501 net::URLRequestStatus::SUCCESS);
502 fake_factory_->SetFakeResponse(
503 GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
504 "some_response",
505 net::HTTP_OK,
506 net::URLRequestStatus::SUCCESS);
507 fake_factory_->SetFakeResponse(
508 GaiaUrls::GetInstance()->oauth2_token_url(),
510 " \"refresh_token\": \"rt1\","
511 " \"access_token\": \"at1\","
512 " \"expires_in\": 3600,"
513 " \"token_type\": \"Bearer\""
514 "}",
515 net::HTTP_OK,
516 net::URLRequestStatus::SUCCESS);
517 fake_factory_->SetFakeResponse(
518 GaiaUrls::GetInstance()->oauth_user_info_url(),
520 " \"id\": \"12345\""
521 "}",
522 net::HTTP_OK,
523 net::URLRequestStatus::SUCCESS);
524 fake_factory_->SetFakeResponse(
525 GaiaUrls::GetInstance()->oauth1_login_url(),
526 "SID=sid\nLSID=lsid\nAuth=auth_token",
527 net::HTTP_OK,
528 net::URLRequestStatus::SUCCESS);
529 fake_factory_->SetFakeResponse(
530 GaiaUrls::GetInstance()->oauth2_revoke_url(),
532 net::HTTP_OK,
533 net::URLRequestStatus::SUCCESS);
536 void SyncTest::SetOAuth2TokenResponse(const std::string& response_data,
537 net::HttpStatusCode response_code,
538 net::URLRequestStatus::Status status) {
539 ASSERT_TRUE(NULL != fake_factory_.get());
540 fake_factory_->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
541 response_data, response_code, status);
544 void SyncTest::ClearMockGaiaResponses() {
545 // Clear any mock gaia responses that might have been set.
546 if (fake_factory_) {
547 fake_factory_->ClearFakeResponses();
548 fake_factory_.reset();
551 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
552 // created.
553 net::URLFetcher::CancelAll();
554 factory_.reset();
557 void SyncTest::DecideServerType() {
558 // Only set |server_type_| if it hasn't already been set. This allows for
559 // tests to explicitly set this value in each test class if needed.
560 if (server_type_ == SERVER_TYPE_UNDECIDED) {
561 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
562 if (!cl->HasSwitch(switches::kSyncServiceURL) &&
563 !cl->HasSwitch(switches::kSyncServerCommandLine)) {
564 // If neither a sync server URL nor a sync server command line is
565 // provided, start up a local sync test server and point Chrome
566 // to its URL. This is the most common configuration, and the only
567 // one that makes sense for most developers. FakeServer is the
568 // current solution but some scenarios are only supported by the
569 // legacy python server.
570 server_type_ = test_type_ == SINGLE_CLIENT || test_type_ == TWO_CLIENT ?
571 IN_PROCESS_FAKE_SERVER : LOCAL_PYTHON_SERVER;
572 } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
573 cl->HasSwitch(switches::kSyncServerCommandLine)) {
574 // If a sync server URL and a sync server command line are provided,
575 // start up a local sync server by running the command line. Chrome
576 // will connect to the server at the URL that was provided.
577 server_type_ = LOCAL_LIVE_SERVER;
578 } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
579 !cl->HasSwitch(switches::kSyncServerCommandLine)) {
580 // If a sync server URL is provided, but not a server command line,
581 // it is assumed that the server is already running. Chrome will
582 // automatically connect to it at the URL provided. There is nothing
583 // to do here.
584 server_type_ = EXTERNAL_LIVE_SERVER;
585 } else {
586 // If a sync server command line is provided, but not a server URL,
587 // we flag an error.
588 LOG(FATAL) << "Can't figure out how to run a server.";
593 // Start up a local sync server based on the value of server_type_, which
594 // was determined from the command line parameters.
595 void SyncTest::SetUpTestServerIfRequired() {
596 if (server_type_ == LOCAL_PYTHON_SERVER) {
597 if (!SetUpLocalPythonTestServer())
598 LOG(FATAL) << "Failed to set up local python sync and XMPP servers";
599 SetupMockGaiaResponses();
600 } else if (server_type_ == LOCAL_LIVE_SERVER) {
601 // Using mock gaia credentials requires the use of a mock XMPP server.
602 if (username_ == "user@gmail.com" && !SetUpLocalPythonTestServer())
603 LOG(FATAL) << "Failed to set up local python XMPP server";
604 if (!SetUpLocalTestServer())
605 LOG(FATAL) << "Failed to set up local test server";
606 } else if (server_type_ == IN_PROCESS_FAKE_SERVER) {
607 fake_server_.reset(new fake_server::FakeServer());
608 // Similar to LOCAL_LIVE_SERVER, we must start this for XMPP.
609 SetUpLocalPythonTestServer();
610 SetupMockGaiaResponses();
611 } else if (server_type_ == EXTERNAL_LIVE_SERVER) {
612 // Nothing to do; we'll just talk to the URL we were given.
613 } else {
614 LOG(FATAL) << "Don't know which server environment to run test in.";
618 bool SyncTest::SetUpLocalPythonTestServer() {
619 EXPECT_TRUE(sync_server_.Start())
620 << "Could not launch local python test server.";
622 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
623 if (server_type_ == LOCAL_PYTHON_SERVER) {
624 std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec();
625 cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url);
626 DVLOG(1) << "Started local python sync server at " << sync_service_url;
629 int xmpp_port = 0;
630 if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) {
631 LOG(ERROR) << "Could not find valid xmpp_port value";
632 return false;
634 if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) {
635 LOG(ERROR) << "Invalid xmpp port: " << xmpp_port;
636 return false;
639 net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair());
640 xmpp_host_port_pair.set_port(xmpp_port);
641 xmpp_port_.reset(new net::ScopedPortException(xmpp_port));
643 if (!cl->HasSwitch(switches::kSyncNotificationHostPort)) {
644 cl->AppendSwitchASCII(switches::kSyncNotificationHostPort,
645 xmpp_host_port_pair.ToString());
646 // The local XMPP server only supports insecure connections.
647 cl->AppendSwitch(switches::kSyncAllowInsecureXmppConnection);
649 DVLOG(1) << "Started local python XMPP server at "
650 << xmpp_host_port_pair.ToString();
652 return true;
655 bool SyncTest::SetUpLocalTestServer() {
656 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
657 base::CommandLine::StringType server_cmdline_string =
658 cl->GetSwitchValueNative(switches::kSyncServerCommandLine);
659 base::CommandLine::StringVector server_cmdline_vector;
660 base::CommandLine::StringType delimiters(FILE_PATH_LITERAL(" "));
661 Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector);
662 base::CommandLine server_cmdline(server_cmdline_vector);
663 base::LaunchOptions options;
664 #if defined(OS_WIN)
665 options.start_hidden = true;
666 #endif
667 if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_))
668 LOG(ERROR) << "Could not launch local test server.";
670 const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout();
671 const int kNumIntervals = 15;
672 if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) {
673 DVLOG(1) << "Started local test server at "
674 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
675 return true;
676 } else {
677 LOG(ERROR) << "Could not start local test server at "
678 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
679 return false;
683 bool SyncTest::TearDownLocalPythonTestServer() {
684 if (!sync_server_.Stop()) {
685 LOG(ERROR) << "Could not stop local python test server.";
686 return false;
688 xmpp_port_.reset();
689 return true;
692 bool SyncTest::TearDownLocalTestServer() {
693 if (test_server_handle_ != base::kNullProcessHandle) {
694 EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false))
695 << "Could not stop local test server.";
696 base::CloseProcessHandle(test_server_handle_);
697 test_server_handle_ = base::kNullProcessHandle;
699 return true;
702 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) {
703 for (int i = 0; i < intervals; ++i) {
704 if (IsTestServerRunning())
705 return true;
706 base::PlatformThread::Sleep(wait / intervals);
708 return false;
711 bool SyncTest::IsTestServerRunning() {
712 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
713 std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL);
714 GURL sync_url_status(sync_url.append("/healthz"));
715 SyncServerStatusChecker delegate;
716 scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
717 sync_url_status, net::URLFetcher::GET, &delegate));
718 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
719 net::LOAD_DO_NOT_SEND_COOKIES |
720 net::LOAD_DO_NOT_SAVE_COOKIES);
721 fetcher->SetRequestContext(g_browser_process->system_request_context());
722 fetcher->Start();
723 content::RunMessageLoop();
724 return delegate.running();
727 void SyncTest::EnableNetwork(Profile* profile) {
728 SetProxyConfig(profile->GetRequestContext(),
729 net::ProxyConfig::CreateDirect());
730 if (notifications_enabled_) {
731 EnableNotificationsImpl();
733 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
734 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
737 void SyncTest::DisableNetwork(Profile* profile) {
738 DisableNotificationsImpl();
739 // Set the current proxy configuration to a nonexistent proxy to effectively
740 // disable networking.
741 net::ProxyConfig config;
742 config.proxy_rules().ParseFromString("http=127.0.0.1:0");
743 SetProxyConfig(profile->GetRequestContext(), config);
744 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
745 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
748 bool SyncTest::TestUsesSelfNotifications() {
749 return true;
752 bool SyncTest::EnableEncryption(int index) {
753 ProfileSyncService* service = GetClient(index)->service();
755 if (::IsEncryptionComplete(service))
756 return true;
758 service->EnableEncryptEverything();
760 // In order to kick off the encryption we have to reconfigure. Just grab the
761 // currently synced types and use them.
762 const syncer::ModelTypeSet synced_datatypes =
763 service->GetPreferredDataTypes();
764 bool sync_everything = synced_datatypes.Equals(syncer::ModelTypeSet::All());
765 service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
767 // Wait some time to let the enryption finish.
768 EncryptionChecker checker(service);
769 checker.Wait();
771 return !checker.TimedOut();
774 bool SyncTest::IsEncryptionComplete(int index) {
775 return ::IsEncryptionComplete(GetClient(index)->service());
778 bool SyncTest::AwaitQuiescence() {
779 return ProfileSyncServiceHarness::AwaitQuiescence(clients());
782 bool SyncTest::ServerSupportsNotificationControl() const {
783 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
785 // Supported only if we're using the python testserver.
786 return server_type_ == LOCAL_PYTHON_SERVER;
789 void SyncTest::DisableNotificationsImpl() {
790 ASSERT_TRUE(ServerSupportsNotificationControl());
791 std::string path = "chromiumsync/disablenotifications";
792 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
793 ASSERT_EQ("Notifications disabled",
794 base::UTF16ToASCII(
795 browser()->tab_strip_model()->GetActiveWebContents()->
796 GetTitle()));
799 void SyncTest::DisableNotifications() {
800 DisableNotificationsImpl();
801 notifications_enabled_ = false;
804 void SyncTest::EnableNotificationsImpl() {
805 ASSERT_TRUE(ServerSupportsNotificationControl());
806 std::string path = "chromiumsync/enablenotifications";
807 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
808 ASSERT_EQ("Notifications enabled",
809 base::UTF16ToASCII(
810 browser()->tab_strip_model()->GetActiveWebContents()->
811 GetTitle()));
814 void SyncTest::EnableNotifications() {
815 EnableNotificationsImpl();
816 notifications_enabled_ = true;
819 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) {
820 ASSERT_TRUE(ServerSupportsNotificationControl());
821 const std::string& data =
822 syncer::P2PNotificationData(
823 "from_server",
824 syncer::NOTIFY_ALL,
825 syncer::ObjectIdInvalidationMap::InvalidateAll(
826 syncer::ModelTypeSetToObjectIdSet(changed_types))).ToString();
827 const std::string& path =
828 std::string("chromiumsync/sendnotification?channel=") +
829 syncer::kSyncP2PNotificationChannel + "&data=" + data;
830 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
831 ASSERT_EQ("Notification sent",
832 base::UTF16ToASCII(
833 browser()->tab_strip_model()->GetActiveWebContents()->
834 GetTitle()));
837 bool SyncTest::ServerSupportsErrorTriggering() const {
838 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
840 // Supported only if we're using the python testserver.
841 return server_type_ == LOCAL_PYTHON_SERVER;
844 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) {
845 ASSERT_TRUE(ServerSupportsErrorTriggering());
846 std::string path = "chromiumsync/migrate";
847 char joiner = '?';
848 for (syncer::ModelTypeSet::Iterator it = model_types.First();
849 it.Good(); it.Inc()) {
850 path.append(
851 base::StringPrintf(
852 "%ctype=%d", joiner,
853 syncer::GetSpecificsFieldNumberFromModelType(it.Get())));
854 joiner = '&';
856 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
857 ASSERT_EQ("Migration: 200",
858 base::UTF16ToASCII(
859 browser()->tab_strip_model()->GetActiveWebContents()->
860 GetTitle()));
863 void SyncTest::TriggerBirthdayError() {
864 ASSERT_TRUE(ServerSupportsErrorTriggering());
865 std::string path = "chromiumsync/birthdayerror";
866 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
867 ASSERT_EQ("Birthday error",
868 base::UTF16ToASCII(
869 browser()->tab_strip_model()->GetActiveWebContents()->
870 GetTitle()));
873 void SyncTest::TriggerTransientError() {
874 ASSERT_TRUE(ServerSupportsErrorTriggering());
875 std::string path = "chromiumsync/transienterror";
876 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
877 ASSERT_EQ("Transient error",
878 base::UTF16ToASCII(
879 browser()->tab_strip_model()->GetActiveWebContents()->
880 GetTitle()));
883 void SyncTest::TriggerAuthState(PythonServerAuthState auth_state) {
884 ASSERT_TRUE(ServerSupportsErrorTriggering());
885 std::string path = "chromiumsync/cred";
886 path.append(auth_state == AUTHENTICATED_TRUE ? "?valid=True" :
887 "?valid=False");
888 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
891 void SyncTest::TriggerXmppAuthError() {
892 ASSERT_TRUE(ServerSupportsErrorTriggering());
893 std::string path = "chromiumsync/xmppcred";
894 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
897 namespace {
899 sync_pb::SyncEnums::ErrorType
900 GetClientToServerResponseErrorType(
901 syncer::SyncProtocolErrorType error) {
902 switch (error) {
903 case syncer::SYNC_SUCCESS:
904 return sync_pb::SyncEnums::SUCCESS;
905 case syncer::NOT_MY_BIRTHDAY:
906 return sync_pb::SyncEnums::NOT_MY_BIRTHDAY;
907 case syncer::THROTTLED:
908 return sync_pb::SyncEnums::THROTTLED;
909 case syncer::CLEAR_PENDING:
910 return sync_pb::SyncEnums::CLEAR_PENDING;
911 case syncer::TRANSIENT_ERROR:
912 return sync_pb::SyncEnums::TRANSIENT_ERROR;
913 case syncer::MIGRATION_DONE:
914 return sync_pb::SyncEnums::MIGRATION_DONE;
915 case syncer::UNKNOWN_ERROR:
916 return sync_pb::SyncEnums::UNKNOWN;
917 default:
918 NOTREACHED();
919 return sync_pb::SyncEnums::UNKNOWN;
923 sync_pb::SyncEnums::Action GetClientToServerResponseAction(
924 const syncer::ClientAction& action) {
925 switch (action) {
926 case syncer::UPGRADE_CLIENT:
927 return sync_pb::SyncEnums::UPGRADE_CLIENT;
928 case syncer::CLEAR_USER_DATA_AND_RESYNC:
929 return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC;
930 case syncer::ENABLE_SYNC_ON_ACCOUNT:
931 return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT;
932 case syncer::STOP_AND_RESTART_SYNC:
933 return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC;
934 case syncer::DISABLE_SYNC_ON_CLIENT:
935 return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT;
936 case syncer::UNKNOWN_ACTION:
937 return sync_pb::SyncEnums::UNKNOWN_ACTION;
938 default:
939 NOTREACHED();
940 return sync_pb::SyncEnums::UNKNOWN_ACTION;
944 } // namespace
946 void SyncTest::TriggerSyncError(const syncer::SyncProtocolError& error,
947 SyncErrorFrequency frequency) {
948 ASSERT_TRUE(ServerSupportsErrorTriggering());
949 std::string path = "chromiumsync/error";
950 int error_type =
951 static_cast<int>(GetClientToServerResponseErrorType(
952 error.error_type));
953 int action = static_cast<int>(GetClientToServerResponseAction(
954 error.action));
956 path.append(base::StringPrintf("?error=%d", error_type));
957 path.append(base::StringPrintf("&action=%d", action));
959 path.append(base::StringPrintf("&error_description=%s",
960 error.error_description.c_str()));
961 path.append(base::StringPrintf("&url=%s", error.url.c_str()));
962 path.append(base::StringPrintf("&frequency=%d", frequency));
964 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
965 std::string output = base::UTF16ToASCII(
966 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
967 ASSERT_TRUE(output.find("SetError: 200") != base::string16::npos);
970 void SyncTest::TriggerCreateSyncedBookmarks() {
971 ASSERT_TRUE(ServerSupportsErrorTriggering());
972 std::string path = "chromiumsync/createsyncedbookmarks";
973 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
974 ASSERT_EQ("Synced Bookmarks",
975 base::UTF16ToASCII(
976 browser()->tab_strip_model()->GetActiveWebContents()->
977 GetTitle()));
980 void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter,
981 const net::ProxyConfig& proxy_config) {
982 base::WaitableEvent done(false, false);
983 BrowserThread::PostTask(
984 BrowserThread::IO, FROM_HERE,
985 base::Bind(&SetProxyConfigCallback, &done,
986 make_scoped_refptr(context_getter), proxy_config));
987 done.Wait();