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