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/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/proxy/proxy_config.h"
70 #include "net/proxy/proxy_config_service_fixed.h"
71 #include "net/proxy/proxy_service.h"
72 #include "net/test/spawned_test_server/spawned_test_server.h"
73 #include "net/url_request/test_url_fetcher_factory.h"
74 #include "net/url_request/url_fetcher.h"
75 #include "net/url_request/url_fetcher_delegate.h"
76 #include "net/url_request/url_request_context.h"
77 #include "net/url_request/url_request_context_getter.h"
78 #include "sync/engine/sync_scheduler_impl.h"
79 #include "sync/protocol/sync.pb.h"
80 #include "sync/test/fake_server/fake_server.h"
81 #include "sync/test/fake_server/fake_server_network_resources.h"
84 #if defined(OS_CHROMEOS)
85 #include "chromeos/chromeos_switches.h"
88 using content::BrowserThread
;
91 const char kPasswordFileForTest
[] = "password-file-for-test";
92 const char kSyncUserForTest
[] = "sync-user-for-test";
93 const char kSyncPasswordForTest
[] = "sync-password-for-test";
94 const char kSyncServerCommandLine
[] = "sync-server-command-line";
99 // Helper class that checks whether a sync test server is running or not.
100 class SyncServerStatusChecker
: public net::URLFetcherDelegate
{
102 SyncServerStatusChecker() : running_(false) {}
104 virtual void OnURLFetchComplete(const net::URLFetcher
* source
) OVERRIDE
{
106 source
->GetResponseAsString(&data
);
108 (source
->GetStatus().status() == net::URLRequestStatus::SUCCESS
&&
109 source
->GetResponseCode() == 200 && data
.find("ok") == 0);
110 base::MessageLoop::current()->Quit();
113 bool running() const { return running_
; }
119 bool IsEncryptionComplete(const ProfileSyncService
* service
) {
120 return service
->EncryptEverythingEnabled() && !service
->encryption_pending();
123 // Helper class to wait for encryption to complete.
124 class EncryptionChecker
: public SingleClientStatusChangeChecker
{
126 explicit EncryptionChecker(ProfileSyncService
* service
)
127 : SingleClientStatusChangeChecker(service
) {}
129 virtual bool IsExitConditionSatisfied() OVERRIDE
{
130 return IsEncryptionComplete(service());
133 virtual std::string
GetDebugMessage() const OVERRIDE
{
138 void SetupNetworkCallback(
139 base::WaitableEvent
* done
,
140 net::URLRequestContextGetter
* url_request_context_getter
) {
141 url_request_context_getter
->GetURLRequestContext()->
142 set_cookie_store(new net::CookieMonster(NULL
, NULL
));
146 void SetProxyConfigCallback(
147 base::WaitableEvent
* done
,
148 net::URLRequestContextGetter
* url_request_context_getter
,
149 const net::ProxyConfig
& proxy_config
) {
150 net::ProxyService
* proxy_service
=
151 url_request_context_getter
->GetURLRequestContext()->proxy_service();
152 proxy_service
->ResetConfigService(
153 new net::ProxyConfigServiceFixed(proxy_config
));
157 KeyedService
* BuildFakeServerProfileInvalidationProvider(
158 content::BrowserContext
* context
) {
159 return new invalidation::ProfileInvalidationProvider(
160 scoped_ptr
<invalidation::InvalidationService
>(
161 new fake_server::FakeServerInvalidationService
));
164 KeyedService
* BuildP2PProfileInvalidationProvider(
165 content::BrowserContext
* context
,
166 syncer::P2PNotificationTarget notification_target
) {
167 Profile
* profile
= static_cast<Profile
*>(context
);
168 return new invalidation::ProfileInvalidationProvider(
169 scoped_ptr
<invalidation::InvalidationService
>(
170 new invalidation::P2PInvalidationService(
171 scoped_ptr
<IdentityProvider
>(new ProfileIdentityProvider(
172 SigninManagerFactory::GetForProfile(profile
),
173 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
174 LoginUIServiceFactory::GetForProfile(profile
))),
175 profile
->GetRequestContext(),
176 notification_target
)));
179 KeyedService
* BuildSelfNotifyingP2PProfileInvalidationProvider(
180 content::BrowserContext
* context
) {
181 return BuildP2PProfileInvalidationProvider(context
, syncer::NOTIFY_ALL
);
184 KeyedService
* BuildRealisticP2PProfileInvalidationProvider(
185 content::BrowserContext
* context
) {
186 return BuildP2PProfileInvalidationProvider(context
, syncer::NOTIFY_OTHERS
);
191 SyncTest::SyncTest(TestType test_type
)
192 : test_type_(test_type
),
193 server_type_(SERVER_TYPE_UNDECIDED
),
196 notifications_enabled_(true),
197 test_server_handle_(base::kNullProcessHandle
) {
198 sync_datatype_helper::AssociateWithTest(this);
199 switch (test_type_
) {
201 case SINGLE_CLIENT_LEGACY
: {
206 case TWO_CLIENT_LEGACY
: {
210 case MULTIPLE_CLIENT
: {
217 SyncTest::~SyncTest() {}
219 void SyncTest::SetUp() {
220 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
221 if (cl
->HasSwitch(switches::kPasswordFileForTest
)) {
223 } else if (cl
->HasSwitch(switches::kSyncUserForTest
) &&
224 cl
->HasSwitch(switches::kSyncPasswordForTest
)) {
225 username_
= cl
->GetSwitchValueASCII(switches::kSyncUserForTest
);
226 password_
= cl
->GetSwitchValueASCII(switches::kSyncPasswordForTest
);
228 username_
= "user@gmail.com";
229 password_
= "password";
232 if (username_
.empty() || password_
.empty())
233 LOG(FATAL
) << "Cannot run sync tests without GAIA credentials.";
235 // Sets |server_type_| if it wasn't specified by the test.
238 // Mock the Mac Keychain service. The real Keychain can block on user input.
239 #if defined(OS_MACOSX)
240 OSCrypt::UseMockKeychain(true);
243 // Start up a sync test server if one is needed and setup mock gaia responses.
244 // Note: This must be done prior to the call to SetupClients() because we want
245 // the mock gaia responses to be available before GaiaUrls is initialized.
246 SetUpTestServerIfRequired();
248 // Yield control back to the InProcessBrowserTest framework.
249 InProcessBrowserTest::SetUp();
252 void SyncTest::TearDown() {
253 // Clear any mock gaia responses that might have been set.
254 ClearMockGaiaResponses();
256 // Allow the InProcessBrowserTest framework to perform its tear down.
257 InProcessBrowserTest::TearDown();
259 // Stop the local python test server. This is a no-op if one wasn't started.
260 TearDownLocalPythonTestServer();
262 // Stop the local sync test server. This is a no-op if one wasn't started.
263 TearDownLocalTestServer();
265 fake_server_
.reset();
268 void SyncTest::SetUpCommandLine(base::CommandLine
* cl
) {
270 AddOptionalTypesToCommandLine(cl
);
272 #if defined(OS_CHROMEOS)
273 cl
->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests
);
277 void SyncTest::AddTestSwitches(base::CommandLine
* cl
) {
278 // Disable non-essential access of external network resources.
279 if (!cl
->HasSwitch(switches::kDisableBackgroundNetworking
))
280 cl
->AppendSwitch(switches::kDisableBackgroundNetworking
);
282 if (!cl
->HasSwitch(switches::kSyncShortInitialRetryOverride
))
283 cl
->AppendSwitch(switches::kSyncShortInitialRetryOverride
);
286 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine
* cl
) {}
289 Profile
* SyncTest::MakeProfile(const base::FilePath::StringType name
) {
291 PathService::Get(chrome::DIR_USER_DATA
, &path
);
292 path
= path
.Append(name
);
294 if (!base::PathExists(path
))
295 CHECK(base::CreateDirectory(path
));
298 Profile::CreateProfile(path
, NULL
, Profile::CREATE_MODE_SYNCHRONOUS
);
299 g_browser_process
->profile_manager()->RegisterTestingProfile(profile
,
305 Profile
* SyncTest::GetProfile(int index
) {
306 if (profiles_
.empty())
307 LOG(FATAL
) << "SetupClients() has not yet been called.";
308 if (index
< 0 || index
>= static_cast<int>(profiles_
.size()))
309 LOG(FATAL
) << "GetProfile(): Index is out of bounds.";
310 return profiles_
[index
];
313 Browser
* SyncTest::GetBrowser(int index
) {
314 if (browsers_
.empty())
315 LOG(FATAL
) << "SetupClients() has not yet been called.";
316 if (index
< 0 || index
>= static_cast<int>(browsers_
.size()))
317 LOG(FATAL
) << "GetBrowser(): Index is out of bounds.";
318 return browsers_
[index
];
321 ProfileSyncServiceHarness
* SyncTest::GetClient(int index
) {
322 if (clients_
.empty())
323 LOG(FATAL
) << "SetupClients() has not yet been called.";
324 if (index
< 0 || index
>= static_cast<int>(clients_
.size()))
325 LOG(FATAL
) << "GetClient(): Index is out of bounds.";
326 return clients_
[index
];
329 ProfileSyncService
* SyncTest::GetSyncService(int index
) {
330 return ProfileSyncServiceFactory::GetForProfile(GetProfile(index
));
333 std::vector
<ProfileSyncService
*> SyncTest::GetSyncServices() {
334 std::vector
<ProfileSyncService
*> services
;
335 for (int i
= 0; i
< num_clients(); ++i
) {
336 services
.push_back(GetSyncService(i
));
341 Profile
* SyncTest::verifier() {
342 if (verifier_
== NULL
)
343 LOG(FATAL
) << "SetupClients() has not yet been called.";
347 void SyncTest::DisableVerifier() {
348 use_verifier_
= false;
351 bool SyncTest::SetupClients() {
352 if (num_clients_
<= 0)
353 LOG(FATAL
) << "num_clients_ incorrectly initialized.";
354 if (!profiles_
.empty() || !browsers_
.empty() || !clients_
.empty())
355 LOG(FATAL
) << "SetupClients() has already been called.";
357 // Create the required number of sync profiles, browsers and clients.
358 profiles_
.resize(num_clients_
);
359 browsers_
.resize(num_clients_
);
360 clients_
.resize(num_clients_
);
361 invalidation_forwarders_
.resize(num_clients_
);
362 fake_server_invalidation_services_
.resize(num_clients_
);
363 for (int i
= 0; i
< num_clients_
; ++i
) {
364 InitializeInstance(i
);
367 // Create the verifier profile.
368 verifier_
= MakeProfile(FILE_PATH_LITERAL("Verifier"));
369 test::WaitForBookmarkModelToLoad(
370 BookmarkModelFactory::GetForProfile(verifier()));
371 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
372 verifier(), Profile::EXPLICIT_ACCESS
));
373 ui_test_utils::WaitForTemplateURLServiceToLoad(
374 TemplateURLServiceFactory::GetForProfile(verifier()));
375 return (verifier_
!= NULL
);
378 void SyncTest::InitializeInstance(int index
) {
379 profiles_
[index
] = MakeProfile(
380 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index
));
381 EXPECT_FALSE(GetProfile(index
) == NULL
) << "Could not create Profile "
384 browsers_
[index
] = new Browser(Browser::CreateParams(
385 GetProfile(index
), chrome::GetActiveDesktop()));
386 EXPECT_FALSE(GetBrowser(index
) == NULL
) << "Could not create Browser "
390 // Make sure the ProfileSyncService has been created before creating the
391 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
393 ProfileSyncService
* profile_sync_service
=
394 ProfileSyncServiceFactory::GetForProfile(GetProfile(index
));
396 SetupNetwork(GetProfile(index
)->GetRequestContext());
398 if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
399 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
400 profile_sync_service
->OverrideNetworkResourcesForTest(
401 make_scoped_ptr
<syncer::NetworkResources
>(
402 new fake_server::FakeServerNetworkResources(fake_server_
.get())));
406 ProfileSyncServiceHarness::Create(
410 EXPECT_FALSE(GetClient(index
) == NULL
) << "Could not create Client "
412 InitializeInvalidations(index
);
414 test::WaitForBookmarkModelToLoad(
415 BookmarkModelFactory::GetForProfile(GetProfile(index
)));
416 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
417 GetProfile(index
), Profile::EXPLICIT_ACCESS
));
418 ui_test_utils::WaitForTemplateURLServiceToLoad(
419 TemplateURLServiceFactory::GetForProfile(GetProfile(index
)));
422 void SyncTest::InitializeInvalidations(int index
) {
423 if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
424 CHECK(fake_server_
.get());
425 fake_server::FakeServerInvalidationService
* invalidation_service
=
426 static_cast<fake_server::FakeServerInvalidationService
*>(
427 static_cast<invalidation::ProfileInvalidationProvider
*>(
428 invalidation::ProfileInvalidationProviderFactory::
429 GetInstance()->SetTestingFactoryAndUse(
431 BuildFakeServerProfileInvalidationProvider
))->
432 GetInvalidationService());
433 fake_server_
->AddObserver(invalidation_service
);
434 if (TestUsesSelfNotifications()) {
435 invalidation_service
->EnableSelfNotifications();
437 invalidation_service
->DisableSelfNotifications();
439 fake_server_invalidation_services_
[index
] = invalidation_service
;
441 invalidation::P2PInvalidationService
* p2p_invalidation_service
=
442 static_cast<invalidation::P2PInvalidationService
*>(
443 static_cast<invalidation::ProfileInvalidationProvider
*>(
444 invalidation::ProfileInvalidationProviderFactory::
445 GetInstance()->SetTestingFactoryAndUse(
447 TestUsesSelfNotifications() ?
448 BuildSelfNotifyingP2PProfileInvalidationProvider
:
449 BuildRealisticP2PProfileInvalidationProvider
))->
450 GetInvalidationService());
451 p2p_invalidation_service
->UpdateCredentials(username_
, password_
);
452 // Start listening for and emitting notifications of commits.
453 invalidation_forwarders_
[index
] =
454 new P2PInvalidationForwarder(clients_
[index
]->service(),
455 p2p_invalidation_service
);
459 bool SyncTest::SetupSync() {
460 // Create sync profiles and clients if they haven't already been created.
461 if (profiles_
.empty()) {
463 LOG(FATAL
) << "SetupClients() failed.";
466 // Sync each of the profiles.
467 for (int i
= 0; i
< num_clients_
; ++i
) {
468 if (!GetClient(i
)->SetupSync())
469 LOG(FATAL
) << "SetupSync() failed.";
472 // Because clients may modify sync data as part of startup (for example local
473 // session-releated data is rewritten), we need to ensure all startup-based
474 // changes have propagated between the clients.
476 // Tests that don't use self-notifications can't await quiescense. They'll
477 // have to find their own way of waiting for an initial state if they really
478 // need such guarantees.
479 if (TestUsesSelfNotifications()) {
486 void SyncTest::TearDownOnMainThread() {
487 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
488 clients_
[i
]->service()->DisableForUser();
491 // Some of the pending messages might rely on browser windows still being
492 // around, so run messages both before and after closing all browsers.
493 content::RunAllPendingInMessageLoop();
494 // Close all browser windows.
495 chrome::CloseAllBrowsers();
496 content::RunAllPendingInMessageLoop();
498 if (fake_server_
.get()) {
499 std::vector
<fake_server::FakeServerInvalidationService
*>::const_iterator it
;
500 for (it
= fake_server_invalidation_services_
.begin();
501 it
!= fake_server_invalidation_services_
.end(); ++it
) {
502 fake_server_
->RemoveObserver(*it
);
506 // All browsers should be closed at this point, or else we could see memory
507 // corruption in QuitBrowser().
508 CHECK_EQ(0U, chrome::GetTotalBrowserCount());
509 invalidation_forwarders_
.clear();
510 fake_server_invalidation_services_
.clear();
514 void SyncTest::SetUpInProcessBrowserTestFixture() {
515 // We don't take a reference to |resolver|, but mock_host_resolver_override_
516 // does, so effectively assumes ownership.
517 net::RuleBasedHostResolverProc
* resolver
=
518 new net::RuleBasedHostResolverProc(host_resolver());
519 resolver
->AllowDirectLookup("*.google.com");
520 // On Linux, we use Chromium's NSS implementation which uses the following
521 // hosts for certificate verification. Without these overrides, running the
522 // integration tests on Linux causes error as we make external DNS lookups.
523 resolver
->AllowDirectLookup("*.thawte.com");
524 resolver
->AllowDirectLookup("*.geotrust.com");
525 resolver
->AllowDirectLookup("*.gstatic.com");
526 mock_host_resolver_override_
.reset(
527 new net::ScopedDefaultHostResolverProc(resolver
));
530 void SyncTest::TearDownInProcessBrowserTestFixture() {
531 mock_host_resolver_override_
.reset();
534 void SyncTest::ReadPasswordFile() {
535 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
536 password_file_
= cl
->GetSwitchValuePath(switches::kPasswordFileForTest
);
537 if (password_file_
.empty())
538 LOG(FATAL
) << "Can't run live server test without specifying --"
539 << switches::kPasswordFileForTest
<< "=<filename>";
540 std::string file_contents
;
541 base::ReadFileToString(password_file_
, &file_contents
);
542 ASSERT_NE(file_contents
, "") << "Password file \""
543 << password_file_
.value() << "\" does not exist.";
544 std::vector
<std::string
> tokens
;
545 std::string delimiters
= "\r\n";
546 Tokenize(file_contents
, delimiters
, &tokens
);
547 ASSERT_EQ(2U, tokens
.size()) << "Password file \""
548 << password_file_
.value()
549 << "\" must contain exactly two lines of text.";
550 username_
= tokens
[0];
551 password_
= tokens
[1];
554 void SyncTest::SetupMockGaiaResponses() {
555 factory_
.reset(new net::URLFetcherImplFactory());
556 fake_factory_
.reset(new net::FakeURLFetcherFactory(factory_
.get()));
557 fake_factory_
->SetFakeResponse(
558 GaiaUrls::GetInstance()->get_user_info_url(),
559 "email=user@gmail.com\ndisplayEmail=user@gmail.com",
561 net::URLRequestStatus::SUCCESS
);
562 fake_factory_
->SetFakeResponse(
563 GaiaUrls::GetInstance()->issue_auth_token_url(),
566 net::URLRequestStatus::SUCCESS
);
567 fake_factory_
->SetFakeResponse(
568 GURL(GoogleURLTracker::kSearchDomainCheckURL
),
571 net::URLRequestStatus::SUCCESS
);
572 fake_factory_
->SetFakeResponse(
573 GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
576 net::URLRequestStatus::SUCCESS
);
577 fake_factory_
->SetFakeResponse(
578 GaiaUrls::GetInstance()->oauth2_token_url(),
580 " \"refresh_token\": \"rt1\","
581 " \"access_token\": \"at1\","
582 " \"expires_in\": 3600,"
583 " \"token_type\": \"Bearer\""
586 net::URLRequestStatus::SUCCESS
);
587 fake_factory_
->SetFakeResponse(
588 GaiaUrls::GetInstance()->oauth_user_info_url(),
593 net::URLRequestStatus::SUCCESS
);
594 fake_factory_
->SetFakeResponse(
595 GaiaUrls::GetInstance()->oauth1_login_url(),
596 "SID=sid\nLSID=lsid\nAuth=auth_token",
598 net::URLRequestStatus::SUCCESS
);
599 fake_factory_
->SetFakeResponse(
600 GaiaUrls::GetInstance()->oauth2_revoke_url(),
603 net::URLRequestStatus::SUCCESS
);
606 void SyncTest::SetOAuth2TokenResponse(const std::string
& response_data
,
607 net::HttpStatusCode response_code
,
608 net::URLRequestStatus::Status status
) {
609 ASSERT_TRUE(NULL
!= fake_factory_
.get());
610 fake_factory_
->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
611 response_data
, response_code
, status
);
614 void SyncTest::ClearMockGaiaResponses() {
615 // Clear any mock gaia responses that might have been set.
617 fake_factory_
->ClearFakeResponses();
618 fake_factory_
.reset();
621 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
623 net::URLFetcher::CancelAll();
627 void SyncTest::DecideServerType() {
628 // Only set |server_type_| if it hasn't already been set. This allows for
629 // tests to explicitly set this value in each test class if needed.
630 if (server_type_
== SERVER_TYPE_UNDECIDED
) {
631 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
632 if (!cl
->HasSwitch(switches::kSyncServiceURL
) &&
633 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
634 // If neither a sync server URL nor a sync server command line is
635 // provided, start up a local sync test server and point Chrome
636 // to its URL. This is the most common configuration, and the only
637 // one that makes sense for most developers. FakeServer is the
638 // current solution but some scenarios are only supported by the
639 // legacy python server.
640 switch (test_type_
) {
643 case MULTIPLE_CLIENT
:
644 server_type_
= IN_PROCESS_FAKE_SERVER
;
647 server_type_
= LOCAL_PYTHON_SERVER
;
649 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
650 cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
651 // If a sync server URL and a sync server command line are provided,
652 // start up a local sync server by running the command line. Chrome
653 // will connect to the server at the URL that was provided.
654 server_type_
= LOCAL_LIVE_SERVER
;
655 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
656 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
657 // If a sync server URL is provided, but not a server command line,
658 // it is assumed that the server is already running. Chrome will
659 // automatically connect to it at the URL provided. There is nothing
661 server_type_
= EXTERNAL_LIVE_SERVER
;
663 // If a sync server command line is provided, but not a server URL,
665 LOG(FATAL
) << "Can't figure out how to run a server.";
670 // Start up a local sync server based on the value of server_type_, which
671 // was determined from the command line parameters.
672 void SyncTest::SetUpTestServerIfRequired() {
673 if (server_type_
== LOCAL_PYTHON_SERVER
) {
674 if (!SetUpLocalPythonTestServer())
675 LOG(FATAL
) << "Failed to set up local python sync and XMPP servers";
676 SetupMockGaiaResponses();
677 } else if (server_type_
== LOCAL_LIVE_SERVER
) {
678 // Using mock gaia credentials requires the use of a mock XMPP server.
679 if (username_
== "user@gmail.com" && !SetUpLocalPythonTestServer())
680 LOG(FATAL
) << "Failed to set up local python XMPP server";
681 if (!SetUpLocalTestServer())
682 LOG(FATAL
) << "Failed to set up local test server";
683 } else if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
684 fake_server_
.reset(new fake_server::FakeServer());
685 SetupMockGaiaResponses();
686 } else if (server_type_
== EXTERNAL_LIVE_SERVER
) {
687 // Nothing to do; we'll just talk to the URL we were given.
689 LOG(FATAL
) << "Don't know which server environment to run test in.";
693 bool SyncTest::SetUpLocalPythonTestServer() {
694 EXPECT_TRUE(sync_server_
.Start())
695 << "Could not launch local python test server.";
697 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
698 if (server_type_
== LOCAL_PYTHON_SERVER
) {
699 std::string sync_service_url
= sync_server_
.GetURL("chromiumsync").spec();
700 cl
->AppendSwitchASCII(switches::kSyncServiceURL
, sync_service_url
);
701 DVLOG(1) << "Started local python sync server at " << sync_service_url
;
705 if (!sync_server_
.server_data().GetInteger("xmpp_port", &xmpp_port
)) {
706 LOG(ERROR
) << "Could not find valid xmpp_port value";
709 if ((xmpp_port
<= 0) || (xmpp_port
> kuint16max
)) {
710 LOG(ERROR
) << "Invalid xmpp port: " << xmpp_port
;
714 net::HostPortPair
xmpp_host_port_pair(sync_server_
.host_port_pair());
715 xmpp_host_port_pair
.set_port(xmpp_port
);
716 xmpp_port_
.reset(new net::ScopedPortException(xmpp_port
));
718 if (!cl
->HasSwitch(invalidation::switches::kSyncNotificationHostPort
)) {
719 cl
->AppendSwitchASCII(invalidation::switches::kSyncNotificationHostPort
,
720 xmpp_host_port_pair
.ToString());
721 // The local XMPP server only supports insecure connections.
722 cl
->AppendSwitch(invalidation::switches::kSyncAllowInsecureXmppConnection
);
724 DVLOG(1) << "Started local python XMPP server at "
725 << xmpp_host_port_pair
.ToString();
730 bool SyncTest::SetUpLocalTestServer() {
731 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
732 base::CommandLine::StringType server_cmdline_string
=
733 cl
->GetSwitchValueNative(switches::kSyncServerCommandLine
);
734 base::CommandLine::StringVector server_cmdline_vector
;
735 base::CommandLine::StringType
delimiters(FILE_PATH_LITERAL(" "));
736 Tokenize(server_cmdline_string
, delimiters
, &server_cmdline_vector
);
737 base::CommandLine
server_cmdline(server_cmdline_vector
);
738 base::LaunchOptions options
;
740 options
.start_hidden
= true;
742 if (!base::LaunchProcess(server_cmdline
, options
, &test_server_handle_
))
743 LOG(ERROR
) << "Could not launch local test server.";
745 const base::TimeDelta kMaxWaitTime
= TestTimeouts::action_max_timeout();
746 const int kNumIntervals
= 15;
747 if (WaitForTestServerToStart(kMaxWaitTime
, kNumIntervals
)) {
748 DVLOG(1) << "Started local test server at "
749 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
752 LOG(ERROR
) << "Could not start local test server at "
753 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
758 bool SyncTest::TearDownLocalPythonTestServer() {
759 if (!sync_server_
.Stop()) {
760 LOG(ERROR
) << "Could not stop local python test server.";
767 bool SyncTest::TearDownLocalTestServer() {
768 if (test_server_handle_
!= base::kNullProcessHandle
) {
769 EXPECT_TRUE(base::KillProcess(test_server_handle_
, 0, false))
770 << "Could not stop local test server.";
771 base::CloseProcessHandle(test_server_handle_
);
772 test_server_handle_
= base::kNullProcessHandle
;
777 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait
, int intervals
) {
778 for (int i
= 0; i
< intervals
; ++i
) {
779 if (IsTestServerRunning())
781 base::PlatformThread::Sleep(wait
/ intervals
);
786 bool SyncTest::IsTestServerRunning() {
787 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
788 std::string sync_url
= cl
->GetSwitchValueASCII(switches::kSyncServiceURL
);
789 GURL
sync_url_status(sync_url
.append("/healthz"));
790 SyncServerStatusChecker delegate
;
791 scoped_ptr
<net::URLFetcher
> fetcher(net::URLFetcher::Create(
792 sync_url_status
, net::URLFetcher::GET
, &delegate
));
793 fetcher
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
794 net::LOAD_DO_NOT_SEND_COOKIES
|
795 net::LOAD_DO_NOT_SAVE_COOKIES
);
796 fetcher
->SetRequestContext(g_browser_process
->system_request_context());
798 content::RunMessageLoop();
799 return delegate
.running();
802 void SyncTest::EnableNetwork(Profile
* profile
) {
803 // TODO(pvalenzuela): Remove this restriction when FakeServer's observers
804 // (namely FakeServerInvaldationService) are aware of a network disconnect.
805 ASSERT_NE(IN_PROCESS_FAKE_SERVER
, server_type_
)
806 << "FakeServer does not support EnableNetwork.";
807 SetProxyConfig(profile
->GetRequestContext(),
808 net::ProxyConfig::CreateDirect());
809 if (notifications_enabled_
) {
810 EnableNotificationsImpl();
812 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
813 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
816 void SyncTest::DisableNetwork(Profile
* profile
) {
817 // TODO(pvalenzuela): Remove this restriction when FakeServer's observers
818 // (namely FakeServerInvaldationService) are aware of a network disconnect.
819 ASSERT_NE(IN_PROCESS_FAKE_SERVER
, server_type_
)
820 << "FakeServer does not support DisableNetwork.";
821 DisableNotificationsImpl();
822 // Set the current proxy configuration to a nonexistent proxy to effectively
823 // disable networking.
824 net::ProxyConfig config
;
825 config
.proxy_rules().ParseFromString("http=127.0.0.1:0");
826 SetProxyConfig(profile
->GetRequestContext(), config
);
827 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
828 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
831 bool SyncTest::TestUsesSelfNotifications() {
835 bool SyncTest::EnableEncryption(int index
) {
836 ProfileSyncService
* service
= GetClient(index
)->service();
838 if (::IsEncryptionComplete(service
))
841 service
->EnableEncryptEverything();
843 // In order to kick off the encryption we have to reconfigure. Just grab the
844 // currently synced types and use them.
845 const syncer::ModelTypeSet synced_datatypes
=
846 service
->GetPreferredDataTypes();
847 bool sync_everything
= synced_datatypes
.Equals(syncer::ModelTypeSet::All());
848 service
->OnUserChoseDatatypes(sync_everything
, synced_datatypes
);
850 return AwaitEncryptionComplete(index
);
853 bool SyncTest::IsEncryptionComplete(int index
) {
854 return ::IsEncryptionComplete(GetClient(index
)->service());
857 bool SyncTest::AwaitEncryptionComplete(int index
) {
858 ProfileSyncService
* service
= GetClient(index
)->service();
859 EncryptionChecker
checker(service
);
861 return !checker
.TimedOut();
864 bool SyncTest::AwaitQuiescence() {
865 return ProfileSyncServiceHarness::AwaitQuiescence(clients());
868 bool SyncTest::ServerSupportsNotificationControl() const {
869 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
871 // Supported only if we're using the python testserver.
872 return server_type_
== LOCAL_PYTHON_SERVER
;
875 void SyncTest::DisableNotificationsImpl() {
876 ASSERT_TRUE(ServerSupportsNotificationControl());
877 std::string path
= "chromiumsync/disablenotifications";
878 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
879 ASSERT_EQ("Notifications disabled",
881 browser()->tab_strip_model()->GetActiveWebContents()->
885 void SyncTest::DisableNotifications() {
886 DisableNotificationsImpl();
887 notifications_enabled_
= false;
890 void SyncTest::EnableNotificationsImpl() {
891 ASSERT_TRUE(ServerSupportsNotificationControl());
892 std::string path
= "chromiumsync/enablenotifications";
893 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
894 ASSERT_EQ("Notifications enabled",
896 browser()->tab_strip_model()->GetActiveWebContents()->
900 void SyncTest::EnableNotifications() {
901 EnableNotificationsImpl();
902 notifications_enabled_
= true;
905 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types
) {
906 ASSERT_TRUE(ServerSupportsNotificationControl());
907 const std::string
& data
=
908 syncer::P2PNotificationData(
911 syncer::ObjectIdInvalidationMap::InvalidateAll(
912 syncer::ModelTypeSetToObjectIdSet(changed_types
))).ToString();
913 const std::string
& path
=
914 std::string("chromiumsync/sendnotification?channel=") +
915 syncer::kSyncP2PNotificationChannel
+ "&data=" + data
;
916 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
917 ASSERT_EQ("Notification sent",
919 browser()->tab_strip_model()->GetActiveWebContents()->
923 bool SyncTest::ServerSupportsErrorTriggering() const {
924 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
926 // Supported only if we're using the python testserver.
927 return server_type_
== LOCAL_PYTHON_SERVER
;
930 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types
) {
931 ASSERT_TRUE(ServerSupportsErrorTriggering());
932 std::string path
= "chromiumsync/migrate";
934 for (syncer::ModelTypeSet::Iterator it
= model_types
.First();
935 it
.Good(); it
.Inc()) {
939 syncer::GetSpecificsFieldNumberFromModelType(it
.Get())));
942 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
943 ASSERT_EQ("Migration: 200",
945 browser()->tab_strip_model()->GetActiveWebContents()->
949 void SyncTest::TriggerTransientError() {
950 ASSERT_TRUE(ServerSupportsErrorTriggering());
951 std::string path
= "chromiumsync/transienterror";
952 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
953 ASSERT_EQ("Transient error",
955 browser()->tab_strip_model()->GetActiveWebContents()->
959 void SyncTest::TriggerXmppAuthError() {
960 ASSERT_TRUE(ServerSupportsErrorTriggering());
961 std::string path
= "chromiumsync/xmppcred";
962 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
967 sync_pb::SyncEnums::ErrorType
968 GetClientToServerResponseErrorType(
969 syncer::SyncProtocolErrorType error
) {
971 case syncer::SYNC_SUCCESS
:
972 return sync_pb::SyncEnums::SUCCESS
;
973 case syncer::NOT_MY_BIRTHDAY
:
974 return sync_pb::SyncEnums::NOT_MY_BIRTHDAY
;
975 case syncer::THROTTLED
:
976 return sync_pb::SyncEnums::THROTTLED
;
977 case syncer::CLEAR_PENDING
:
978 return sync_pb::SyncEnums::CLEAR_PENDING
;
979 case syncer::TRANSIENT_ERROR
:
980 return sync_pb::SyncEnums::TRANSIENT_ERROR
;
981 case syncer::MIGRATION_DONE
:
982 return sync_pb::SyncEnums::MIGRATION_DONE
;
983 case syncer::UNKNOWN_ERROR
:
984 return sync_pb::SyncEnums::UNKNOWN
;
985 case syncer::INVALID_CREDENTIAL
:
986 NOTREACHED(); // NOTREACHED() because auth error is not set through
987 // error code in sync response.
988 return sync_pb::SyncEnums::UNKNOWN
;
989 case syncer::DISABLED_BY_ADMIN
:
990 return sync_pb::SyncEnums::DISABLED_BY_ADMIN
;
991 case syncer::USER_ROLLBACK
:
992 return sync_pb::SyncEnums::USER_ROLLBACK
;
993 case syncer::NON_RETRIABLE_ERROR
:
994 return sync_pb::SyncEnums::UNKNOWN
;
996 return sync_pb::SyncEnums::UNKNOWN
;
999 sync_pb::SyncEnums::Action
GetClientToServerResponseAction(
1000 const syncer::ClientAction
& action
) {
1002 case syncer::UPGRADE_CLIENT
:
1003 return sync_pb::SyncEnums::UPGRADE_CLIENT
;
1004 case syncer::CLEAR_USER_DATA_AND_RESYNC
:
1005 return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC
;
1006 case syncer::ENABLE_SYNC_ON_ACCOUNT
:
1007 return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT
;
1008 case syncer::STOP_AND_RESTART_SYNC
:
1009 return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC
;
1010 case syncer::DISABLE_SYNC_ON_CLIENT
:
1011 return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT
;
1012 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT
:
1013 case syncer::DISABLE_SYNC_AND_ROLLBACK
:
1014 case syncer::ROLLBACK_DONE
:
1015 NOTREACHED(); // No corresponding proto action for these. Shouldn't
1017 return sync_pb::SyncEnums::UNKNOWN_ACTION
;
1018 case syncer::UNKNOWN_ACTION
:
1019 return sync_pb::SyncEnums::UNKNOWN_ACTION
;
1021 return sync_pb::SyncEnums::UNKNOWN_ACTION
;
1026 void SyncTest::TriggerSyncError(const syncer::SyncProtocolError
& error
,
1027 SyncErrorFrequency frequency
) {
1028 ASSERT_TRUE(ServerSupportsErrorTriggering());
1029 std::string path
= "chromiumsync/error";
1031 static_cast<int>(GetClientToServerResponseErrorType(
1033 int action
= static_cast<int>(GetClientToServerResponseAction(
1036 path
.append(base::StringPrintf("?error=%d", error_type
));
1037 path
.append(base::StringPrintf("&action=%d", action
));
1039 path
.append(base::StringPrintf("&error_description=%s",
1040 error
.error_description
.c_str()));
1041 path
.append(base::StringPrintf("&url=%s", error
.url
.c_str()));
1042 path
.append(base::StringPrintf("&frequency=%d", frequency
));
1044 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1045 std::string output
= base::UTF16ToASCII(
1046 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
1047 ASSERT_TRUE(output
.find("SetError: 200") != base::string16::npos
);
1050 void SyncTest::TriggerCreateSyncedBookmarks() {
1051 ASSERT_TRUE(ServerSupportsErrorTriggering());
1052 std::string path
= "chromiumsync/createsyncedbookmarks";
1053 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1054 ASSERT_EQ("Synced Bookmarks",
1056 browser()->tab_strip_model()->GetActiveWebContents()->
1060 void SyncTest::SetupNetwork(net::URLRequestContextGetter
* context_getter
) {
1061 base::WaitableEvent
done(false, false);
1062 BrowserThread::PostTask(
1063 BrowserThread::IO
, FROM_HERE
,
1064 base::Bind(&SetupNetworkCallback
, &done
,
1065 make_scoped_refptr(context_getter
)));
1069 void SyncTest::SetProxyConfig(net::URLRequestContextGetter
* context_getter
,
1070 const net::ProxyConfig
& proxy_config
) {
1071 base::WaitableEvent
done(false, false);
1072 BrowserThread::PostTask(
1073 BrowserThread::IO
, FROM_HERE
,
1074 base::Bind(&SetProxyConfigCallback
, &done
,
1075 make_scoped_refptr(context_getter
), proxy_config
));
1079 fake_server::FakeServer
* SyncTest::GetFakeServer() const {
1080 return fake_server_
.get();