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