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