Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / sync_test.cc
blob6d5f0e026069ed792d7ae81b296c7fb4f39c3b5c
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/memory/ref_counted.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/process/launch.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/test/test_timeouts.h"
21 #include "base/threading/platform_thread.h"
22 #include "base/values.h"
23 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
24 #include "chrome/browser/history/history_service_factory.h"
25 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
26 #include "chrome/browser/lifetime/application_lifetime.h"
27 #include "chrome/browser/profiles/profile_manager.h"
28 #include "chrome/browser/search_engines/template_url_service_factory.h"
29 #include "chrome/browser/signin/profile_identity_provider.h"
30 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
31 #include "chrome/browser/signin/signin_manager_factory.h"
32 #include "chrome/browser/sync/glue/invalidation_helper.h"
33 #include "chrome/browser/sync/profile_sync_service.h"
34 #include "chrome/browser/sync/profile_sync_service_factory.h"
35 #include "chrome/browser/sync/test/integration/fake_server_invalidation_service.h"
36 #include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h"
37 #include "chrome/browser/sync/test/integration/p2p_sync_refresher.h"
38 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
39 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
40 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
41 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
42 #include "chrome/browser/ui/browser.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/host_desktop.h"
45 #include "chrome/browser/ui/tabs/tab_strip_model.h"
46 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
47 #include "chrome/common/chrome_constants.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/bookmarks/test/bookmark_test_helpers.h"
53 #include "components/google/core/browser/google_url_tracker.h"
54 #include "components/invalidation/invalidation_service.h"
55 #include "components/invalidation/invalidation_switches.h"
56 #include "components/invalidation/p2p_invalidation_service.h"
57 #include "components/invalidation/p2p_invalidator.h"
58 #include "components/invalidation/profile_invalidation_provider.h"
59 #include "components/keyed_service/core/keyed_service.h"
60 #include "components/os_crypt/os_crypt.h"
61 #include "components/search_engines/template_url_service.h"
62 #include "components/signin/core/browser/signin_manager.h"
63 #include "content/public/browser/web_contents.h"
64 #include "content/public/test/test_browser_thread.h"
65 #include "google_apis/gaia/gaia_urls.h"
66 #include "net/base/escape.h"
67 #include "net/base/load_flags.h"
68 #include "net/base/network_change_notifier.h"
69 #include "net/cookies/cookie_monster.h"
70 #include "net/test/spawned_test_server/spawned_test_server.h"
71 #include "net/url_request/test_url_fetcher_factory.h"
72 #include "net/url_request/url_fetcher.h"
73 #include "net/url_request/url_fetcher_delegate.h"
74 #include "net/url_request/url_request_context.h"
75 #include "net/url_request/url_request_context_getter.h"
76 #include "sync/engine/sync_scheduler_impl.h"
77 #include "sync/protocol/sync.pb.h"
78 #include "sync/test/fake_server/fake_server.h"
79 #include "sync/test/fake_server/fake_server_network_resources.h"
80 #include "url/gurl.h"
82 #if defined(OS_CHROMEOS)
83 #include "chromeos/chromeos_switches.h"
84 #endif
86 using content::BrowserThread;
88 namespace switches {
89 const char kPasswordFileForTest[] = "password-file-for-test";
90 const char kSyncUserForTest[] = "sync-user-for-test";
91 const char kSyncPasswordForTest[] = "sync-password-for-test";
92 const char kSyncServerCommandLine[] = "sync-server-command-line";
95 namespace {
97 // Helper class that checks whether a sync test server is running or not.
98 class SyncServerStatusChecker : public net::URLFetcherDelegate {
99 public:
100 SyncServerStatusChecker() : running_(false) {}
102 void OnURLFetchComplete(const net::URLFetcher* source) override {
103 std::string data;
104 source->GetResponseAsString(&data);
105 running_ =
106 (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
107 source->GetResponseCode() == 200 && data.find("ok") == 0);
108 base::MessageLoop::current()->Quit();
111 bool running() const { return running_; }
113 private:
114 bool running_;
117 bool IsEncryptionComplete(const ProfileSyncService* service) {
118 return service->EncryptEverythingEnabled() && !service->encryption_pending();
121 // Helper class to wait for encryption to complete.
122 class EncryptionChecker : public SingleClientStatusChangeChecker {
123 public:
124 explicit EncryptionChecker(ProfileSyncService* service)
125 : SingleClientStatusChangeChecker(service) {}
127 bool IsExitConditionSatisfied() override {
128 return IsEncryptionComplete(service());
131 std::string GetDebugMessage() const override { return "Encryption"; }
134 void SetupNetworkCallback(
135 base::WaitableEvent* done,
136 net::URLRequestContextGetter* url_request_context_getter) {
137 url_request_context_getter->GetURLRequestContext()->
138 set_cookie_store(new net::CookieMonster(NULL, NULL));
139 done->Signal();
142 KeyedService* BuildFakeServerProfileInvalidationProvider(
143 content::BrowserContext* context) {
144 return new invalidation::ProfileInvalidationProvider(
145 scoped_ptr<invalidation::InvalidationService>(
146 new fake_server::FakeServerInvalidationService));
149 KeyedService* BuildP2PProfileInvalidationProvider(
150 content::BrowserContext* context,
151 syncer::P2PNotificationTarget notification_target) {
152 Profile* profile = static_cast<Profile*>(context);
153 return new invalidation::ProfileInvalidationProvider(
154 scoped_ptr<invalidation::InvalidationService>(
155 new invalidation::P2PInvalidationService(
156 scoped_ptr<IdentityProvider>(new ProfileIdentityProvider(
157 SigninManagerFactory::GetForProfile(profile),
158 ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
159 LoginUIServiceFactory::GetForProfile(profile))),
160 profile->GetRequestContext(),
161 notification_target)));
164 KeyedService* BuildSelfNotifyingP2PProfileInvalidationProvider(
165 content::BrowserContext* context) {
166 return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_ALL);
169 KeyedService* BuildRealisticP2PProfileInvalidationProvider(
170 content::BrowserContext* context) {
171 return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_OTHERS);
174 } // namespace
176 SyncTest::SyncTest(TestType test_type)
177 : test_type_(test_type),
178 server_type_(SERVER_TYPE_UNDECIDED),
179 num_clients_(-1),
180 use_verifier_(true),
181 notifications_enabled_(true) {
182 sync_datatype_helper::AssociateWithTest(this);
183 switch (test_type_) {
184 case SINGLE_CLIENT:
185 case SINGLE_CLIENT_LEGACY: {
186 num_clients_ = 1;
187 break;
189 case TWO_CLIENT:
190 case TWO_CLIENT_LEGACY: {
191 num_clients_ = 2;
192 break;
194 case MULTIPLE_CLIENT: {
195 num_clients_ = 3;
196 break;
201 SyncTest::~SyncTest() {}
203 void SyncTest::SetUp() {
204 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
205 if (cl->HasSwitch(switches::kPasswordFileForTest)) {
206 ReadPasswordFile();
207 } else if (cl->HasSwitch(switches::kSyncUserForTest) &&
208 cl->HasSwitch(switches::kSyncPasswordForTest)) {
209 username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest);
210 password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest);
211 } else {
212 username_ = "user@gmail.com";
213 password_ = "password";
216 if (username_.empty() || password_.empty())
217 LOG(FATAL) << "Cannot run sync tests without GAIA credentials.";
219 // Sets |server_type_| if it wasn't specified by the test.
220 DecideServerType();
222 // Mock the Mac Keychain service. The real Keychain can block on user input.
223 #if defined(OS_MACOSX)
224 OSCrypt::UseMockKeychain(true);
225 #endif
227 // Start up a sync test server if one is needed and setup mock gaia responses.
228 // Note: This must be done prior to the call to SetupClients() because we want
229 // the mock gaia responses to be available before GaiaUrls is initialized.
230 SetUpTestServerIfRequired();
232 // Yield control back to the InProcessBrowserTest framework.
233 InProcessBrowserTest::SetUp();
236 void SyncTest::TearDown() {
237 // Clear any mock gaia responses that might have been set.
238 ClearMockGaiaResponses();
240 // Allow the InProcessBrowserTest framework to perform its tear down.
241 InProcessBrowserTest::TearDown();
243 // Stop the local python test server. This is a no-op if one wasn't started.
244 TearDownLocalPythonTestServer();
246 // Stop the local sync test server. This is a no-op if one wasn't started.
247 TearDownLocalTestServer();
249 fake_server_.reset();
252 void SyncTest::SetUpCommandLine(base::CommandLine* cl) {
253 AddTestSwitches(cl);
254 AddOptionalTypesToCommandLine(cl);
256 #if defined(OS_CHROMEOS)
257 cl->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests);
258 #endif
261 void SyncTest::AddTestSwitches(base::CommandLine* cl) {
262 // Disable non-essential access of external network resources.
263 if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
264 cl->AppendSwitch(switches::kDisableBackgroundNetworking);
266 if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
267 cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
270 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine* cl) {}
272 // Called when the ProfileManager has created a profile.
273 // static
274 void SyncTest::CreateProfileCallback(const base::Closure& quit_closure,
275 Profile* profile,
276 Profile::CreateStatus status) {
277 EXPECT_TRUE(profile);
278 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
279 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
280 // This will be called multiple times. Wait until the profile is initialized
281 // fully to quit the loop.
282 if (status == Profile::CREATE_STATUS_INITIALIZED)
283 quit_closure.Run();
286 // TODO(shadi): Ideally creating a new profile should not depend on signin
287 // process. We should try to consolidate MakeProfileForUISignin() and
288 // MakeProfile(). Major differences are profile paths and creation methods. For
289 // UI signin we need profiles in unique user data dir's and we need to use
290 // ProfileManager::CreateProfileAsync() for proper profile creation.
291 // static
292 Profile* SyncTest::MakeProfileForUISignin(
293 const base::FilePath::StringType name) {
294 // For multi profile UI signin, profile paths should be outside user data dir.
295 // Otherwise, we get an error that the profile has already signed in on this
296 // device.
297 // Note that prefix |name| is implemented only on Win. On other platforms the
298 // com.google.Chrome.XXXXXX prefix is used.
299 base::FilePath profile_path;
300 CHECK(base::CreateNewTempDirectory(name, &profile_path));
302 ProfileManager* profile_manager = g_browser_process->profile_manager();
303 base::RunLoop run_loop;
304 ProfileManager::CreateCallback create_callback = base::Bind(
305 &CreateProfileCallback, run_loop.QuitClosure());
306 profile_manager->CreateProfileAsync(profile_path,
307 create_callback,
308 base::string16(),
309 base::string16(),
310 std::string());
311 run_loop.Run();
312 return profile_manager->GetProfileByPath(profile_path);
315 Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) {
316 base::FilePath path;
317 // Create new profiles in user data dir so that other profiles can know about
318 // it. This is needed in tests such as supervised user cases which assume
319 // browser->profile() as the custodian profile.
320 PathService::Get(chrome::DIR_USER_DATA, &path);
321 path = path.Append(name);
323 if (!base::PathExists(path))
324 CHECK(base::CreateDirectory(path));
326 if (!preexisting_preferences_file_contents_.empty()) {
327 base::FilePath pref_path(path.Append(chrome::kPreferencesFilename));
328 const char* contents = preexisting_preferences_file_contents_.c_str();
329 size_t contents_length = preexisting_preferences_file_contents_.size();
330 if (!base::WriteFile(pref_path, contents, contents_length)) {
331 LOG(FATAL) << "Preexisting Preferences file could not be written.";
335 Profile* profile =
336 Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
337 g_browser_process->profile_manager()->RegisterTestingProfile(profile,
338 true,
339 true);
340 return profile;
343 Profile* SyncTest::GetProfile(int index) {
344 if (profiles_.empty())
345 LOG(FATAL) << "SetupClients() has not yet been called.";
346 if (index < 0 || index >= static_cast<int>(profiles_.size()))
347 LOG(FATAL) << "GetProfile(): Index is out of bounds.";
348 return profiles_[index];
351 Browser* SyncTest::GetBrowser(int index) {
352 if (browsers_.empty())
353 LOG(FATAL) << "SetupClients() has not yet been called.";
354 if (index < 0 || index >= static_cast<int>(browsers_.size()))
355 LOG(FATAL) << "GetBrowser(): Index is out of bounds.";
356 return browsers_[index];
359 ProfileSyncServiceHarness* SyncTest::GetClient(int index) {
360 if (clients_.empty())
361 LOG(FATAL) << "SetupClients() has not yet been called.";
362 if (index < 0 || index >= static_cast<int>(clients_.size()))
363 LOG(FATAL) << "GetClient(): Index is out of bounds.";
364 return clients_[index];
367 ProfileSyncService* SyncTest::GetSyncService(int index) {
368 return ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
371 std::vector<ProfileSyncService*> SyncTest::GetSyncServices() {
372 std::vector<ProfileSyncService*> services;
373 for (int i = 0; i < num_clients(); ++i) {
374 services.push_back(GetSyncService(i));
376 return services;
379 Profile* SyncTest::verifier() {
380 if (verifier_ == NULL)
381 LOG(FATAL) << "SetupClients() has not yet been called.";
382 return verifier_;
385 void SyncTest::DisableVerifier() {
386 use_verifier_ = false;
389 bool SyncTest::SetupClients() {
390 if (num_clients_ <= 0)
391 LOG(FATAL) << "num_clients_ incorrectly initialized.";
392 if (!profiles_.empty() || !browsers_.empty() || !clients_.empty())
393 LOG(FATAL) << "SetupClients() has already been called.";
395 // Create the required number of sync profiles, browsers and clients.
396 profiles_.resize(num_clients_);
397 browsers_.resize(num_clients_);
398 clients_.resize(num_clients_);
399 invalidation_forwarders_.resize(num_clients_);
400 sync_refreshers_.resize(num_clients_);
401 fake_server_invalidation_services_.resize(num_clients_);
402 for (int i = 0; i < num_clients_; ++i) {
403 InitializeInstance(i);
406 // Create the verifier profile.
407 verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier"));
408 bookmarks::test::WaitForBookmarkModelToLoad(
409 BookmarkModelFactory::GetForProfile(verifier()));
410 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
411 verifier(), ServiceAccessType::EXPLICIT_ACCESS));
412 ui_test_utils::WaitForTemplateURLServiceToLoad(
413 TemplateURLServiceFactory::GetForProfile(verifier()));
414 return (verifier_ != NULL);
417 void SyncTest::InitializeInstance(int index) {
418 base::FilePath::StringType profile_name =
419 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index);
420 // If running against an EXTERNAL_LIVE_SERVER, we need to signin profiles
421 // using real GAIA server. This requires creating profiles with no test hooks.
422 if (server_type_ == EXTERNAL_LIVE_SERVER) {
423 profiles_[index] = MakeProfileForUISignin(profile_name);
424 } else {
425 // Without need of real GAIA authentication, we create new test profiles.
426 profiles_[index] = MakeProfile(profile_name);
429 EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile "
430 << index << ".";
432 // CheckInitialState() assumes that no windows are open at startup.
433 browsers_[index] = new Browser(Browser::CreateParams(
434 GetProfile(index), chrome::GetActiveDesktop()));
436 EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser "
437 << index << ".";
439 // Make sure the ProfileSyncService has been created before creating the
440 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
441 // already exist.
442 ProfileSyncService* profile_sync_service =
443 ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
445 SetupNetwork(GetProfile(index)->GetRequestContext());
447 if (server_type_ == IN_PROCESS_FAKE_SERVER) {
448 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
449 profile_sync_service->OverrideNetworkResourcesForTest(
450 make_scoped_ptr<syncer::NetworkResources>(
451 new fake_server::FakeServerNetworkResources(fake_server_.get())));
454 ProfileSyncServiceHarness::SigninType singin_type =
455 (server_type_ == EXTERNAL_LIVE_SERVER)
456 ? ProfileSyncServiceHarness::SigninType::UI_SIGNIN
457 : ProfileSyncServiceHarness::SigninType::FAKE_SIGNIN;
459 clients_[index] =
460 ProfileSyncServiceHarness::Create(GetProfile(index),
461 username_,
462 password_,
463 singin_type);
464 EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client "
465 << index << ".";
466 InitializeInvalidations(index);
468 bookmarks::test::WaitForBookmarkModelToLoad(
469 BookmarkModelFactory::GetForProfile(GetProfile(index)));
470 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
471 GetProfile(index), ServiceAccessType::EXPLICIT_ACCESS));
472 ui_test_utils::WaitForTemplateURLServiceToLoad(
473 TemplateURLServiceFactory::GetForProfile(GetProfile(index)));
476 void SyncTest::InitializeInvalidations(int index) {
477 if (server_type_ == IN_PROCESS_FAKE_SERVER) {
478 CHECK(fake_server_.get());
479 fake_server::FakeServerInvalidationService* invalidation_service =
480 static_cast<fake_server::FakeServerInvalidationService*>(
481 static_cast<invalidation::ProfileInvalidationProvider*>(
482 invalidation::ProfileInvalidationProviderFactory::
483 GetInstance()->SetTestingFactoryAndUse(
484 GetProfile(index),
485 BuildFakeServerProfileInvalidationProvider))->
486 GetInvalidationService());
487 fake_server_->AddObserver(invalidation_service);
488 if (TestUsesSelfNotifications()) {
489 invalidation_service->EnableSelfNotifications();
490 } else {
491 invalidation_service->DisableSelfNotifications();
493 fake_server_invalidation_services_[index] = invalidation_service;
494 } else if (server_type_ == EXTERNAL_LIVE_SERVER) {
495 // DO NOTHING. External live sync servers use GCM to notify profiles of any
496 // invalidations in sync'ed data. In this case, to notify other profiles of
497 // invalidations, we use sync refresh notifications instead.
498 } else {
499 invalidation::P2PInvalidationService* p2p_invalidation_service =
500 static_cast<invalidation::P2PInvalidationService*>(
501 static_cast<invalidation::ProfileInvalidationProvider*>(
502 invalidation::ProfileInvalidationProviderFactory::
503 GetInstance()->SetTestingFactoryAndUse(
504 GetProfile(index),
505 TestUsesSelfNotifications() ?
506 BuildSelfNotifyingP2PProfileInvalidationProvider :
507 BuildRealisticP2PProfileInvalidationProvider))->
508 GetInvalidationService());
509 p2p_invalidation_service->UpdateCredentials(username_, password_);
510 // Start listening for and emitting notifications of commits.
511 invalidation_forwarders_[index] =
512 new P2PInvalidationForwarder(clients_[index]->service(),
513 p2p_invalidation_service);
517 bool SyncTest::SetupSync() {
518 // Create sync profiles and clients if they haven't already been created.
519 if (profiles_.empty()) {
520 if (!SetupClients())
521 LOG(FATAL) << "SetupClients() failed.";
524 // Sync each of the profiles.
525 for (int i = 0; i < num_clients_; ++i) {
526 if (!GetClient(i)->SetupSync())
527 LOG(FATAL) << "SetupSync() failed.";
530 // Because clients may modify sync data as part of startup (for example local
531 // session-releated data is rewritten), we need to ensure all startup-based
532 // changes have propagated between the clients.
534 // Tests that don't use self-notifications can't await quiescense. They'll
535 // have to find their own way of waiting for an initial state if they really
536 // need such guarantees.
537 if (TestUsesSelfNotifications()) {
538 AwaitQuiescence();
541 // SyncRefresher is used instead of invalidations to notify other profiles to
542 // do a sync refresh on committed data sets. This is only needed when running
543 // tests against external live server, otherwise invalidation service is used.
544 // With external live servers, the profiles commit data on first sync cycle
545 // automatically after signing in. To avoid misleading sync commit
546 // notifications at start up, we start the SyncRefresher observers post
547 // client set up.
548 if (server_type_ == EXTERNAL_LIVE_SERVER) {
549 for (int i = 0; i < num_clients_; ++i) {
550 sync_refreshers_[i] = new P2PSyncRefresher(clients_[i]->service());
554 return true;
557 void SyncTest::TearDownOnMainThread() {
558 for (size_t i = 0; i < clients_.size(); ++i) {
559 clients_[i]->service()->DisableForUser();
562 // Some of the pending messages might rely on browser windows still being
563 // around, so run messages both before and after closing all browsers.
564 content::RunAllPendingInMessageLoop();
565 // Close all browser windows.
566 chrome::CloseAllBrowsers();
567 content::RunAllPendingInMessageLoop();
569 if (fake_server_.get()) {
570 std::vector<fake_server::FakeServerInvalidationService*>::const_iterator it;
571 for (it = fake_server_invalidation_services_.begin();
572 it != fake_server_invalidation_services_.end(); ++it) {
573 fake_server_->RemoveObserver(*it);
577 // All browsers should be closed at this point, or else we could see memory
578 // corruption in QuitBrowser().
579 CHECK_EQ(0U, chrome::GetTotalBrowserCount());
580 invalidation_forwarders_.clear();
581 sync_refreshers_.clear();
582 fake_server_invalidation_services_.clear();
583 clients_.clear();
586 void SyncTest::SetUpInProcessBrowserTestFixture() {
587 // We don't take a reference to |resolver|, but mock_host_resolver_override_
588 // does, so effectively assumes ownership.
589 net::RuleBasedHostResolverProc* resolver =
590 new net::RuleBasedHostResolverProc(host_resolver());
591 resolver->AllowDirectLookup("*.google.com");
592 // On Linux, we use Chromium's NSS implementation which uses the following
593 // hosts for certificate verification. Without these overrides, running the
594 // integration tests on Linux causes error as we make external DNS lookups.
595 resolver->AllowDirectLookup("*.thawte.com");
596 resolver->AllowDirectLookup("*.geotrust.com");
597 resolver->AllowDirectLookup("*.gstatic.com");
598 mock_host_resolver_override_.reset(
599 new net::ScopedDefaultHostResolverProc(resolver));
602 void SyncTest::TearDownInProcessBrowserTestFixture() {
603 mock_host_resolver_override_.reset();
606 void SyncTest::ReadPasswordFile() {
607 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
608 password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest);
609 if (password_file_.empty())
610 LOG(FATAL) << "Can't run live server test without specifying --"
611 << switches::kPasswordFileForTest << "=<filename>";
612 std::string file_contents;
613 base::ReadFileToString(password_file_, &file_contents);
614 ASSERT_NE(file_contents, "") << "Password file \""
615 << password_file_.value() << "\" does not exist.";
616 std::vector<std::string> tokens;
617 std::string delimiters = "\r\n";
618 Tokenize(file_contents, delimiters, &tokens);
619 ASSERT_EQ(2U, tokens.size()) << "Password file \""
620 << password_file_.value()
621 << "\" must contain exactly two lines of text.";
622 username_ = tokens[0];
623 password_ = tokens[1];
626 void SyncTest::SetupMockGaiaResponses() {
627 factory_.reset(new net::URLFetcherImplFactory());
628 fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
629 fake_factory_->SetFakeResponse(
630 GaiaUrls::GetInstance()->get_user_info_url(),
631 "email=user@gmail.com\ndisplayEmail=user@gmail.com",
632 net::HTTP_OK,
633 net::URLRequestStatus::SUCCESS);
634 fake_factory_->SetFakeResponse(
635 GaiaUrls::GetInstance()->issue_auth_token_url(),
636 "auth",
637 net::HTTP_OK,
638 net::URLRequestStatus::SUCCESS);
639 fake_factory_->SetFakeResponse(
640 GURL(GoogleURLTracker::kSearchDomainCheckURL),
641 ".google.com",
642 net::HTTP_OK,
643 net::URLRequestStatus::SUCCESS);
644 fake_factory_->SetFakeResponse(
645 GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
646 "some_response",
647 net::HTTP_OK,
648 net::URLRequestStatus::SUCCESS);
649 fake_factory_->SetFakeResponse(
650 GaiaUrls::GetInstance()->oauth2_token_url(),
652 " \"refresh_token\": \"rt1\","
653 " \"access_token\": \"at1\","
654 " \"expires_in\": 3600,"
655 " \"token_type\": \"Bearer\""
656 "}",
657 net::HTTP_OK,
658 net::URLRequestStatus::SUCCESS);
659 fake_factory_->SetFakeResponse(
660 GaiaUrls::GetInstance()->oauth_user_info_url(),
662 " \"id\": \"12345\""
663 "}",
664 net::HTTP_OK,
665 net::URLRequestStatus::SUCCESS);
666 fake_factory_->SetFakeResponse(
667 GaiaUrls::GetInstance()->oauth1_login_url(),
668 "SID=sid\nLSID=lsid\nAuth=auth_token",
669 net::HTTP_OK,
670 net::URLRequestStatus::SUCCESS);
671 fake_factory_->SetFakeResponse(
672 GaiaUrls::GetInstance()->oauth2_revoke_url(),
674 net::HTTP_OK,
675 net::URLRequestStatus::SUCCESS);
678 void SyncTest::SetOAuth2TokenResponse(const std::string& response_data,
679 net::HttpStatusCode response_code,
680 net::URLRequestStatus::Status status) {
681 ASSERT_TRUE(NULL != fake_factory_.get());
682 fake_factory_->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
683 response_data, response_code, status);
686 void SyncTest::ClearMockGaiaResponses() {
687 // Clear any mock gaia responses that might have been set.
688 if (fake_factory_) {
689 fake_factory_->ClearFakeResponses();
690 fake_factory_.reset();
693 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
694 // created.
695 net::URLFetcher::CancelAll();
696 factory_.reset();
699 void SyncTest::DecideServerType() {
700 // Only set |server_type_| if it hasn't already been set. This allows for
701 // tests to explicitly set this value in each test class if needed.
702 if (server_type_ == SERVER_TYPE_UNDECIDED) {
703 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
704 if (!cl->HasSwitch(switches::kSyncServiceURL) &&
705 !cl->HasSwitch(switches::kSyncServerCommandLine)) {
706 // If neither a sync server URL nor a sync server command line is
707 // provided, start up a local sync test server and point Chrome
708 // to its URL. This is the most common configuration, and the only
709 // one that makes sense for most developers. FakeServer is the
710 // current solution but some scenarios are only supported by the
711 // legacy python server.
712 switch (test_type_) {
713 case SINGLE_CLIENT:
714 case TWO_CLIENT:
715 case MULTIPLE_CLIENT:
716 server_type_ = IN_PROCESS_FAKE_SERVER;
717 break;
718 default:
719 server_type_ = LOCAL_PYTHON_SERVER;
721 } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
722 cl->HasSwitch(switches::kSyncServerCommandLine)) {
723 // If a sync server URL and a sync server command line are provided,
724 // start up a local sync server by running the command line. Chrome
725 // will connect to the server at the URL that was provided.
726 server_type_ = LOCAL_LIVE_SERVER;
727 } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
728 !cl->HasSwitch(switches::kSyncServerCommandLine)) {
729 // If a sync server URL is provided, but not a server command line,
730 // it is assumed that the server is already running. Chrome will
731 // automatically connect to it at the URL provided. There is nothing
732 // to do here.
733 server_type_ = EXTERNAL_LIVE_SERVER;
734 } else {
735 // If a sync server command line is provided, but not a server URL,
736 // we flag an error.
737 LOG(FATAL) << "Can't figure out how to run a server.";
742 // Start up a local sync server based on the value of server_type_, which
743 // was determined from the command line parameters.
744 void SyncTest::SetUpTestServerIfRequired() {
745 if (server_type_ == LOCAL_PYTHON_SERVER) {
746 if (!SetUpLocalPythonTestServer())
747 LOG(FATAL) << "Failed to set up local python sync and XMPP servers";
748 SetupMockGaiaResponses();
749 } else if (server_type_ == LOCAL_LIVE_SERVER) {
750 // Using mock gaia credentials requires the use of a mock XMPP server.
751 if (username_ == "user@gmail.com" && !SetUpLocalPythonTestServer())
752 LOG(FATAL) << "Failed to set up local python XMPP server";
753 if (!SetUpLocalTestServer())
754 LOG(FATAL) << "Failed to set up local test server";
755 } else if (server_type_ == IN_PROCESS_FAKE_SERVER) {
756 fake_server_.reset(new fake_server::FakeServer());
757 SetupMockGaiaResponses();
758 } else if (server_type_ == EXTERNAL_LIVE_SERVER) {
759 // Nothing to do; we'll just talk to the URL we were given.
760 } else {
761 LOG(FATAL) << "Don't know which server environment to run test in.";
765 bool SyncTest::SetUpLocalPythonTestServer() {
766 EXPECT_TRUE(sync_server_.Start())
767 << "Could not launch local python test server.";
769 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
770 if (server_type_ == LOCAL_PYTHON_SERVER) {
771 std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec();
772 cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url);
773 DVLOG(1) << "Started local python sync server at " << sync_service_url;
776 int xmpp_port = 0;
777 if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) {
778 LOG(ERROR) << "Could not find valid xmpp_port value";
779 return false;
781 if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) {
782 LOG(ERROR) << "Invalid xmpp port: " << xmpp_port;
783 return false;
786 net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair());
787 xmpp_host_port_pair.set_port(xmpp_port);
788 xmpp_port_.reset(new net::ScopedPortException(xmpp_port));
790 if (!cl->HasSwitch(invalidation::switches::kSyncNotificationHostPort)) {
791 cl->AppendSwitchASCII(invalidation::switches::kSyncNotificationHostPort,
792 xmpp_host_port_pair.ToString());
793 // The local XMPP server only supports insecure connections.
794 cl->AppendSwitch(invalidation::switches::kSyncAllowInsecureXmppConnection);
796 DVLOG(1) << "Started local python XMPP server at "
797 << xmpp_host_port_pair.ToString();
799 return true;
802 bool SyncTest::SetUpLocalTestServer() {
803 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
804 base::CommandLine::StringType server_cmdline_string =
805 cl->GetSwitchValueNative(switches::kSyncServerCommandLine);
806 base::CommandLine::StringVector server_cmdline_vector;
807 base::CommandLine::StringType delimiters(FILE_PATH_LITERAL(" "));
808 Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector);
809 base::CommandLine server_cmdline(server_cmdline_vector);
810 base::LaunchOptions options;
811 #if defined(OS_WIN)
812 options.start_hidden = true;
813 #endif
814 test_server_ = base::LaunchProcess(server_cmdline, options);
815 if (!test_server_.IsValid())
816 LOG(ERROR) << "Could not launch local test server.";
818 const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout();
819 const int kNumIntervals = 15;
820 if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) {
821 DVLOG(1) << "Started local test server at "
822 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
823 return true;
824 } else {
825 LOG(ERROR) << "Could not start local test server at "
826 << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
827 return false;
831 bool SyncTest::TearDownLocalPythonTestServer() {
832 if (!sync_server_.Stop()) {
833 LOG(ERROR) << "Could not stop local python test server.";
834 return false;
836 xmpp_port_.reset();
837 return true;
840 bool SyncTest::TearDownLocalTestServer() {
841 if (test_server_.IsValid()) {
842 EXPECT_TRUE(test_server_.Terminate(0, false))
843 << "Could not stop local test server.";
844 test_server_.Close();
846 return true;
849 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) {
850 for (int i = 0; i < intervals; ++i) {
851 if (IsTestServerRunning())
852 return true;
853 base::PlatformThread::Sleep(wait / intervals);
855 return false;
858 bool SyncTest::IsTestServerRunning() {
859 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
860 std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL);
861 GURL sync_url_status(sync_url.append("/healthz"));
862 SyncServerStatusChecker delegate;
863 scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
864 sync_url_status, net::URLFetcher::GET, &delegate));
865 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
866 net::LOAD_DO_NOT_SEND_COOKIES |
867 net::LOAD_DO_NOT_SAVE_COOKIES);
868 fetcher->SetRequestContext(g_browser_process->system_request_context());
869 fetcher->Start();
870 content::RunMessageLoop();
871 return delegate.running();
874 bool SyncTest::TestUsesSelfNotifications() {
875 return true;
878 bool SyncTest::EnableEncryption(int index) {
879 ProfileSyncService* service = GetClient(index)->service();
881 if (::IsEncryptionComplete(service))
882 return true;
884 service->EnableEncryptEverything();
886 // In order to kick off the encryption we have to reconfigure. Just grab the
887 // currently synced types and use them.
888 const syncer::ModelTypeSet synced_datatypes =
889 service->GetPreferredDataTypes();
890 bool sync_everything = synced_datatypes.Equals(syncer::ModelTypeSet::All());
891 service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
893 return AwaitEncryptionComplete(index);
896 bool SyncTest::IsEncryptionComplete(int index) {
897 return ::IsEncryptionComplete(GetClient(index)->service());
900 bool SyncTest::AwaitEncryptionComplete(int index) {
901 ProfileSyncService* service = GetClient(index)->service();
902 EncryptionChecker checker(service);
903 checker.Wait();
904 return !checker.TimedOut();
907 bool SyncTest::AwaitQuiescence() {
908 return ProfileSyncServiceHarness::AwaitQuiescence(clients());
911 bool SyncTest::ServerSupportsNotificationControl() const {
912 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
914 // Supported only if we're using the python testserver.
915 return server_type_ == LOCAL_PYTHON_SERVER;
918 void SyncTest::DisableNotificationsImpl() {
919 ASSERT_TRUE(ServerSupportsNotificationControl());
920 std::string path = "chromiumsync/disablenotifications";
921 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
922 ASSERT_EQ("Notifications disabled",
923 base::UTF16ToASCII(
924 browser()->tab_strip_model()->GetActiveWebContents()->
925 GetTitle()));
928 void SyncTest::DisableNotifications() {
929 DisableNotificationsImpl();
930 notifications_enabled_ = false;
933 void SyncTest::EnableNotificationsImpl() {
934 ASSERT_TRUE(ServerSupportsNotificationControl());
935 std::string path = "chromiumsync/enablenotifications";
936 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
937 ASSERT_EQ("Notifications enabled",
938 base::UTF16ToASCII(
939 browser()->tab_strip_model()->GetActiveWebContents()->
940 GetTitle()));
943 void SyncTest::EnableNotifications() {
944 EnableNotificationsImpl();
945 notifications_enabled_ = true;
948 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) {
949 ASSERT_TRUE(ServerSupportsNotificationControl());
950 const std::string& data =
951 syncer::P2PNotificationData(
952 "from_server",
953 syncer::NOTIFY_ALL,
954 syncer::ObjectIdInvalidationMap::InvalidateAll(
955 syncer::ModelTypeSetToObjectIdSet(changed_types))).ToString();
956 const std::string& path =
957 std::string("chromiumsync/sendnotification?channel=") +
958 syncer::kSyncP2PNotificationChannel + "&data=" + data;
959 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
960 ASSERT_EQ("Notification sent",
961 base::UTF16ToASCII(
962 browser()->tab_strip_model()->GetActiveWebContents()->
963 GetTitle()));
966 bool SyncTest::ServerSupportsErrorTriggering() const {
967 EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
969 // Supported only if we're using the python testserver.
970 return server_type_ == LOCAL_PYTHON_SERVER;
973 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) {
974 ASSERT_TRUE(ServerSupportsErrorTriggering());
975 std::string path = "chromiumsync/migrate";
976 char joiner = '?';
977 for (syncer::ModelTypeSet::Iterator it = model_types.First();
978 it.Good(); it.Inc()) {
979 path.append(
980 base::StringPrintf(
981 "%ctype=%d", joiner,
982 syncer::GetSpecificsFieldNumberFromModelType(it.Get())));
983 joiner = '&';
985 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
986 ASSERT_EQ("Migration: 200",
987 base::UTF16ToASCII(
988 browser()->tab_strip_model()->GetActiveWebContents()->
989 GetTitle()));
992 void SyncTest::TriggerXmppAuthError() {
993 ASSERT_TRUE(ServerSupportsErrorTriggering());
994 std::string path = "chromiumsync/xmppcred";
995 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
998 void SyncTest::TriggerCreateSyncedBookmarks() {
999 ASSERT_TRUE(ServerSupportsErrorTriggering());
1000 std::string path = "chromiumsync/createsyncedbookmarks";
1001 ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
1002 ASSERT_EQ("Synced Bookmarks",
1003 base::UTF16ToASCII(
1004 browser()->tab_strip_model()->GetActiveWebContents()->
1005 GetTitle()));
1008 void SyncTest::SetupNetwork(net::URLRequestContextGetter* context_getter) {
1009 base::WaitableEvent done(false, false);
1010 BrowserThread::PostTask(
1011 BrowserThread::IO, FROM_HERE,
1012 base::Bind(&SetupNetworkCallback, &done,
1013 make_scoped_refptr(context_getter)));
1014 done.Wait();
1017 fake_server::FakeServer* SyncTest::GetFakeServer() const {
1018 return fake_server_.get();
1021 void SyncTest::SetPreexistingPreferencesFileContents(
1022 const std::string& contents) {
1023 preexisting_preferences_file_contents_ = contents;