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/guid.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/process/launch.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/test/test_timeouts.h"
24 #include "base/threading/platform_thread.h"
25 #include "base/values.h"
26 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
27 #include "chrome/browser/chrome_notification_types.h"
28 #include "chrome/browser/history/history_service_factory.h"
29 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
30 #include "chrome/browser/lifetime/application_lifetime.h"
31 #include "chrome/browser/profiles/profile_manager.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
34 #include "chrome/browser/signin/signin_manager_factory.h"
35 #include "chrome/browser/sync/profile_sync_service.h"
36 #include "chrome/browser/sync/profile_sync_service_factory.h"
37 #include "chrome/browser/sync/test/integration/fake_server_invalidation_service.h"
38 #include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h"
39 #include "chrome/browser/sync/test/integration/p2p_sync_refresher.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.h"
49 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
50 #include "chrome/common/chrome_constants.h"
51 #include "chrome/common/chrome_paths.h"
52 #include "chrome/common/chrome_switches.h"
53 #include "chrome/test/base/testing_browser_process.h"
54 #include "chrome/test/base/ui_test_utils.h"
55 #include "components/bookmarks/test/bookmark_test_helpers.h"
56 #include "components/google/core/browser/google_url_tracker.h"
57 #include "components/invalidation/impl/invalidation_switches.h"
58 #include "components/invalidation/impl/p2p_invalidation_service.h"
59 #include "components/invalidation/impl/p2p_invalidator.h"
60 #include "components/invalidation/impl/profile_invalidation_provider.h"
61 #include "components/invalidation/public/invalidation_service.h"
62 #include "components/keyed_service/core/keyed_service.h"
63 #include "components/os_crypt/os_crypt.h"
64 #include "components/search_engines/template_url_service.h"
65 #include "components/signin/core/browser/profile_identity_provider.h"
66 #include "components/signin/core/browser/signin_manager.h"
67 #include "components/sync_driver/invalidation_helper.h"
68 #include "components/sync_driver/sync_driver_switches.h"
69 #include "content/public/browser/navigation_entry.h"
70 #include "content/public/browser/notification_service.h"
71 #include "content/public/browser/web_contents.h"
72 #include "content/public/test/test_browser_thread.h"
73 #include "google_apis/gaia/gaia_urls.h"
74 #include "net/base/escape.h"
75 #include "net/base/load_flags.h"
76 #include "net/base/network_change_notifier.h"
77 #include "net/base/port_util.h"
78 #include "net/cookies/cookie_monster.h"
79 #include "net/test/spawned_test_server/spawned_test_server.h"
80 #include "net/url_request/test_url_fetcher_factory.h"
81 #include "net/url_request/url_fetcher.h"
82 #include "net/url_request/url_fetcher_delegate.h"
83 #include "net/url_request/url_request_context.h"
84 #include "net/url_request/url_request_context_getter.h"
85 #include "sync/engine/sync_scheduler_impl.h"
86 #include "sync/protocol/sync.pb.h"
87 #include "sync/test/fake_server/fake_server.h"
88 #include "sync/test/fake_server/fake_server_network_resources.h"
91 #if defined(OS_CHROMEOS)
92 #include "chromeos/chromeos_switches.h"
95 using content::BrowserThread
;
98 const char kPasswordFileForTest
[] = "password-file-for-test";
99 const char kSyncUserForTest
[] = "sync-user-for-test";
100 const char kSyncPasswordForTest
[] = "sync-password-for-test";
101 const char kSyncServerCommandLine
[] = "sync-server-command-line";
106 // Helper class that checks whether a sync test server is running or not.
107 class SyncServerStatusChecker
: public net::URLFetcherDelegate
{
109 SyncServerStatusChecker() : running_(false) {}
111 void OnURLFetchComplete(const net::URLFetcher
* source
) override
{
113 source
->GetResponseAsString(&data
);
115 (source
->GetStatus().status() == net::URLRequestStatus::SUCCESS
&&
116 source
->GetResponseCode() == 200 && data
.find("ok") == 0);
117 base::MessageLoop::current()->Quit();
120 bool running() const { return running_
; }
126 bool IsEncryptionComplete(const ProfileSyncService
* service
) {
127 return service
->EncryptEverythingEnabled() && !service
->encryption_pending();
130 // Helper class to wait for encryption to complete.
131 class EncryptionChecker
: public SingleClientStatusChangeChecker
{
133 explicit EncryptionChecker(ProfileSyncService
* service
)
134 : SingleClientStatusChangeChecker(service
) {}
136 bool IsExitConditionSatisfied() override
{
137 return IsEncryptionComplete(service());
140 std::string
GetDebugMessage() const override
{ return "Encryption"; }
143 void SetupNetworkCallback(
144 base::WaitableEvent
* done
,
145 net::URLRequestContextGetter
* url_request_context_getter
) {
146 url_request_context_getter
->GetURLRequestContext()->
147 set_cookie_store(new net::CookieMonster(NULL
, NULL
));
151 scoped_ptr
<KeyedService
> BuildFakeServerProfileInvalidationProvider(
152 content::BrowserContext
* context
) {
153 return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
154 scoped_ptr
<invalidation::InvalidationService
>(
155 new fake_server::FakeServerInvalidationService
)));
158 scoped_ptr
<KeyedService
> BuildP2PProfileInvalidationProvider(
159 content::BrowserContext
* context
,
160 syncer::P2PNotificationTarget notification_target
) {
161 Profile
* profile
= static_cast<Profile
*>(context
);
162 return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
163 scoped_ptr
<invalidation::InvalidationService
>(
164 new invalidation::P2PInvalidationService(
165 scoped_ptr
<IdentityProvider
>(new ProfileIdentityProvider(
166 SigninManagerFactory::GetForProfile(profile
),
167 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
168 LoginUIServiceFactory::GetShowLoginPopupCallbackForProfile(
170 profile
->GetRequestContext(), notification_target
))));
173 scoped_ptr
<KeyedService
> BuildSelfNotifyingP2PProfileInvalidationProvider(
174 content::BrowserContext
* context
) {
175 return BuildP2PProfileInvalidationProvider(context
, syncer::NOTIFY_ALL
);
178 scoped_ptr
<KeyedService
> BuildRealisticP2PProfileInvalidationProvider(
179 content::BrowserContext
* context
) {
180 return BuildP2PProfileInvalidationProvider(context
, syncer::NOTIFY_OTHERS
);
185 SyncTest::SyncTest(TestType test_type
)
186 : test_type_(test_type
),
187 server_type_(SERVER_TYPE_UNDECIDED
),
190 notifications_enabled_(true),
191 create_gaia_account_at_runtime_(false) {
192 sync_datatype_helper::AssociateWithTest(this);
193 switch (test_type_
) {
195 case SINGLE_CLIENT_LEGACY
: {
200 case TWO_CLIENT_LEGACY
: {
204 case MULTIPLE_CLIENT
: {
211 SyncTest::~SyncTest() {}
213 void SyncTest::SetUp() {
214 // Sets |server_type_| if it wasn't specified by the test.
217 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
218 if (cl
->HasSwitch(switches::kPasswordFileForTest
)) {
221 // Decide on username to use or create one.
222 if (cl
->HasSwitch(switches::kSyncUserForTest
)) {
223 username_
= cl
->GetSwitchValueASCII(switches::kSyncUserForTest
);
224 } else if (UsingExternalServers()) {
225 // We assume the need to automatically create a Gaia account which
226 // requires URL navigation and needs to be done outside SetUp() function.
227 create_gaia_account_at_runtime_
= true;
228 username_
= base::GenerateGUID();
230 username_
= "user@gmail.com";
232 // Decide on password to use.
233 password_
= cl
->HasSwitch(switches::kSyncPasswordForTest
)
234 ? cl
->GetSwitchValueASCII(switches::kSyncPasswordForTest
)
238 if (username_
.empty() || password_
.empty())
239 LOG(FATAL
) << "Cannot run sync tests without GAIA credentials.";
241 // Mock the Mac Keychain service. The real Keychain can block on user input.
242 #if defined(OS_MACOSX)
243 OSCrypt::UseMockKeychain(true);
246 // Start up a sync test server if one is needed and setup mock gaia responses.
247 // Note: This must be done prior to the call to SetupClients() because we want
248 // the mock gaia responses to be available before GaiaUrls is initialized.
249 SetUpTestServerIfRequired();
251 // Yield control back to the InProcessBrowserTest framework.
252 InProcessBrowserTest::SetUp();
255 void SyncTest::TearDown() {
256 // Clear any mock gaia responses that might have been set.
257 ClearMockGaiaResponses();
259 // Allow the InProcessBrowserTest framework to perform its tear down.
260 InProcessBrowserTest::TearDown();
262 // Stop the local python test server. This is a no-op if one wasn't started.
263 TearDownLocalPythonTestServer();
265 // Stop the local sync test server. This is a no-op if one wasn't started.
266 TearDownLocalTestServer();
268 fake_server_
.reset();
271 void SyncTest::SetUpCommandLine(base::CommandLine
* cl
) {
273 AddOptionalTypesToCommandLine(cl
);
275 #if defined(OS_CHROMEOS)
276 cl
->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests
);
280 void SyncTest::AddTestSwitches(base::CommandLine
* cl
) {
281 // Disable non-essential access of external network resources.
282 if (!cl
->HasSwitch(switches::kDisableBackgroundNetworking
))
283 cl
->AppendSwitch(switches::kDisableBackgroundNetworking
);
285 if (!cl
->HasSwitch(switches::kSyncShortInitialRetryOverride
))
286 cl
->AppendSwitch(switches::kSyncShortInitialRetryOverride
);
289 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine
* cl
) {}
291 bool SyncTest::CreateGaiaAccount(const std::string
& username
,
292 const std::string
& password
) {
293 std::string relative_url
= base::StringPrintf("/CreateUsers?%s=%s",
296 GURL create_user_url
=
297 GaiaUrls::GetInstance()->gaia_url().Resolve(relative_url
);
298 // NavigateToURL blocks until the navigation finishes.
299 ui_test_utils::NavigateToURL(browser(), create_user_url
);
300 content::WebContents
* contents
=
301 browser()->tab_strip_model()->GetActiveWebContents();
302 content::NavigationEntry
* entry
= contents
->GetController().GetVisibleEntry();
303 CHECK(entry
) << "Could not get a hold on NavigationEntry post URL navigate.";
304 DVLOG(1) << "Create Gaia account request return code = "
305 << entry
->GetHttpStatusCode();
306 return entry
->GetHttpStatusCode() == 200;
309 // Called when the ProfileManager has created a profile.
311 void SyncTest::CreateProfileCallback(const base::Closure
& quit_closure
,
313 Profile::CreateStatus status
) {
314 EXPECT_TRUE(profile
);
315 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL
, status
);
316 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL
, status
);
317 // This will be called multiple times. Wait until the profile is initialized
318 // fully to quit the loop.
319 if (status
== Profile::CREATE_STATUS_INITIALIZED
)
323 // TODO(shadi): Ideally creating a new profile should not depend on signin
324 // process. We should try to consolidate MakeProfileForUISignin() and
325 // MakeProfile(). Major differences are profile paths and creation methods. For
326 // UI signin we need profiles in unique user data dir's and we need to use
327 // ProfileManager::CreateProfileAsync() for proper profile creation.
329 Profile
* SyncTest::MakeProfileForUISignin(
330 const base::FilePath::StringType name
) {
331 // For multi profile UI signin, profile paths should be outside user data dir.
332 // Otherwise, we get an error that the profile has already signed in on this
334 // Note that prefix |name| is implemented only on Win. On other platforms the
335 // com.google.Chrome.XXXXXX prefix is used.
336 base::FilePath profile_path
;
337 CHECK(base::CreateNewTempDirectory(name
, &profile_path
));
339 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
340 base::RunLoop run_loop
;
341 ProfileManager::CreateCallback create_callback
= base::Bind(
342 &CreateProfileCallback
, run_loop
.QuitClosure());
343 profile_manager
->CreateProfileAsync(profile_path
,
349 return profile_manager
->GetProfileByPath(profile_path
);
352 Profile
* SyncTest::MakeProfile(const base::FilePath::StringType name
) {
354 // Create new profiles in user data dir so that other profiles can know about
355 // it. This is needed in tests such as supervised user cases which assume
356 // browser->profile() as the custodian profile.
357 PathService::Get(chrome::DIR_USER_DATA
, &path
);
358 path
= path
.Append(name
);
360 if (!base::PathExists(path
))
361 CHECK(base::CreateDirectory(path
));
363 if (!preexisting_preferences_file_contents_
.empty()) {
364 base::FilePath
pref_path(path
.Append(chrome::kPreferencesFilename
));
365 const char* contents
= preexisting_preferences_file_contents_
.c_str();
366 size_t contents_length
= preexisting_preferences_file_contents_
.size();
367 if (!base::WriteFile(pref_path
, contents
, contents_length
)) {
368 LOG(FATAL
) << "Preexisting Preferences file could not be written.";
373 Profile::CreateProfile(path
, NULL
, Profile::CREATE_MODE_SYNCHRONOUS
);
374 g_browser_process
->profile_manager()->RegisterTestingProfile(profile
,
380 Profile
* SyncTest::GetProfile(int index
) {
381 if (profiles_
.empty())
382 LOG(FATAL
) << "SetupClients() has not yet been called.";
383 if (index
< 0 || index
>= static_cast<int>(profiles_
.size()))
384 LOG(FATAL
) << "GetProfile(): Index is out of bounds.";
385 return profiles_
[index
];
388 Browser
* SyncTest::GetBrowser(int index
) {
389 if (browsers_
.empty())
390 LOG(FATAL
) << "SetupClients() has not yet been called.";
391 if (index
< 0 || index
>= static_cast<int>(browsers_
.size()))
392 LOG(FATAL
) << "GetBrowser(): Index is out of bounds.";
393 return browsers_
[index
];
396 ProfileSyncServiceHarness
* SyncTest::GetClient(int index
) {
397 if (clients_
.empty())
398 LOG(FATAL
) << "SetupClients() has not yet been called.";
399 if (index
< 0 || index
>= static_cast<int>(clients_
.size()))
400 LOG(FATAL
) << "GetClient(): Index is out of bounds.";
401 return clients_
[index
];
404 ProfileSyncService
* SyncTest::GetSyncService(int index
) {
405 return ProfileSyncServiceFactory::GetForProfile(GetProfile(index
));
408 std::vector
<ProfileSyncService
*> SyncTest::GetSyncServices() {
409 std::vector
<ProfileSyncService
*> services
;
410 for (int i
= 0; i
< num_clients(); ++i
) {
411 services
.push_back(GetSyncService(i
));
416 Profile
* SyncTest::verifier() {
418 LOG(FATAL
) << "Verifier account is disabled.";
419 if (verifier_
== NULL
)
420 LOG(FATAL
) << "SetupClients() has not yet been called.";
424 void SyncTest::DisableVerifier() {
425 use_verifier_
= false;
428 bool SyncTest::SetupClients() {
429 if (num_clients_
<= 0)
430 LOG(FATAL
) << "num_clients_ incorrectly initialized.";
431 if (!profiles_
.empty() || !browsers_
.empty() || !clients_
.empty())
432 LOG(FATAL
) << "SetupClients() has already been called.";
434 // Create the required number of sync profiles, browsers and clients.
435 profiles_
.resize(num_clients_
);
436 browsers_
.resize(num_clients_
);
437 clients_
.resize(num_clients_
);
438 invalidation_forwarders_
.resize(num_clients_
);
439 sync_refreshers_
.resize(num_clients_
);
440 fake_server_invalidation_services_
.resize(num_clients_
);
441 for (int i
= 0; i
< num_clients_
; ++i
) {
442 InitializeInstance(i
);
445 // Verifier account is not useful when running against external servers.
446 if (UsingExternalServers())
449 // Create the verifier profile.
451 verifier_
= MakeProfile(FILE_PATH_LITERAL("Verifier"));
452 bookmarks::test::WaitForBookmarkModelToLoad(
453 BookmarkModelFactory::GetForProfile(verifier()));
454 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
455 verifier(), ServiceAccessType::EXPLICIT_ACCESS
));
456 ui_test_utils::WaitForTemplateURLServiceToLoad(
457 TemplateURLServiceFactory::GetForProfile(verifier()));
459 // Error cases are all handled by LOG(FATAL) messages. So there is not really
460 // a case that returns false. In case we failed to create a verifier profile,
461 // any call to the verifier() would fail.
465 void SyncTest::InitializeInstance(int index
) {
466 base::FilePath::StringType profile_name
=
467 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index
);
468 // If running against an EXTERNAL_LIVE_SERVER, we need to signin profiles
469 // using real GAIA server. This requires creating profiles with no test hooks.
470 if (UsingExternalServers()) {
471 profiles_
[index
] = MakeProfileForUISignin(profile_name
);
473 // Without need of real GAIA authentication, we create new test profiles.
474 profiles_
[index
] = MakeProfile(profile_name
);
477 EXPECT_FALSE(GetProfile(index
) == NULL
) << "Could not create Profile "
480 // CheckInitialState() assumes that no windows are open at startup.
481 browsers_
[index
] = new Browser(Browser::CreateParams(
482 GetProfile(index
), chrome::GetActiveDesktop()));
484 EXPECT_FALSE(GetBrowser(index
) == NULL
) << "Could not create Browser "
487 // Make sure the ProfileSyncService has been created before creating the
488 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
490 ProfileSyncService
* profile_sync_service
=
491 ProfileSyncServiceFactory::GetForProfile(GetProfile(index
));
493 SetupNetwork(GetProfile(index
)->GetRequestContext());
495 if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
496 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
497 profile_sync_service
->OverrideNetworkResourcesForTest(
498 make_scoped_ptr
<syncer::NetworkResources
>(
499 new fake_server::FakeServerNetworkResources(
500 fake_server_
->AsWeakPtr())));
503 ProfileSyncServiceHarness::SigninType singin_type
= UsingExternalServers()
504 ? ProfileSyncServiceHarness::SigninType::UI_SIGNIN
505 : ProfileSyncServiceHarness::SigninType::FAKE_SIGNIN
;
508 ProfileSyncServiceHarness::Create(GetProfile(index
),
512 EXPECT_FALSE(GetClient(index
) == NULL
) << "Could not create Client "
514 InitializeInvalidations(index
);
516 bookmarks::test::WaitForBookmarkModelToLoad(
517 BookmarkModelFactory::GetForProfile(GetProfile(index
)));
518 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
519 GetProfile(index
), ServiceAccessType::EXPLICIT_ACCESS
));
520 ui_test_utils::WaitForTemplateURLServiceToLoad(
521 TemplateURLServiceFactory::GetForProfile(GetProfile(index
)));
524 void SyncTest::InitializeInvalidations(int index
) {
525 if (UsingExternalServers()) {
526 // DO NOTHING. External live sync servers use GCM to notify profiles of any
527 // invalidations in sync'ed data. In this case, to notify other profiles of
528 // invalidations, we use sync refresh notifications instead.
529 } else if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
530 CHECK(fake_server_
.get());
531 fake_server::FakeServerInvalidationService
* invalidation_service
=
532 static_cast<fake_server::FakeServerInvalidationService
*>(
533 static_cast<invalidation::ProfileInvalidationProvider
*>(
534 invalidation::ProfileInvalidationProviderFactory::
535 GetInstance()->SetTestingFactoryAndUse(
537 BuildFakeServerProfileInvalidationProvider
))->
538 GetInvalidationService());
539 fake_server_
->AddObserver(invalidation_service
);
540 if (TestUsesSelfNotifications()) {
541 invalidation_service
->EnableSelfNotifications();
543 invalidation_service
->DisableSelfNotifications();
545 fake_server_invalidation_services_
[index
] = invalidation_service
;
547 invalidation::P2PInvalidationService
* p2p_invalidation_service
=
548 static_cast<invalidation::P2PInvalidationService
*>(
549 static_cast<invalidation::ProfileInvalidationProvider
*>(
550 invalidation::ProfileInvalidationProviderFactory::
551 GetInstance()->SetTestingFactoryAndUse(
553 TestUsesSelfNotifications() ?
554 BuildSelfNotifyingP2PProfileInvalidationProvider
:
555 BuildRealisticP2PProfileInvalidationProvider
))->
556 GetInvalidationService());
557 p2p_invalidation_service
->UpdateCredentials(username_
, password_
);
558 // Start listening for and emitting notifications of commits.
559 invalidation_forwarders_
[index
] =
560 new P2PInvalidationForwarder(clients_
[index
]->service(),
561 p2p_invalidation_service
);
565 bool SyncTest::SetupSync() {
566 if (create_gaia_account_at_runtime_
) {
567 CHECK(UsingExternalServers()) <<
568 "Cannot create Gaia accounts without external authentication servers";
569 if (!CreateGaiaAccount(username_
, password_
))
570 LOG(FATAL
) << "Could not create Gaia account.";
572 // Create sync profiles and clients if they haven't already been created.
573 if (profiles_
.empty()) {
575 LOG(FATAL
) << "SetupClients() failed.";
578 // Sync each of the profiles.
579 for (int i
= 0; i
< num_clients_
; ++i
) {
580 if (!GetClient(i
)->SetupSync())
581 LOG(FATAL
) << "SetupSync() failed.";
584 // Because clients may modify sync data as part of startup (for example local
585 // session-releated data is rewritten), we need to ensure all startup-based
586 // changes have propagated between the clients.
588 // Tests that don't use self-notifications can't await quiescense. They'll
589 // have to find their own way of waiting for an initial state if they really
590 // need such guarantees.
591 if (TestUsesSelfNotifications()) {
595 // SyncRefresher is used instead of invalidations to notify other profiles to
596 // do a sync refresh on committed data sets. This is only needed when running
597 // tests against external live server, otherwise invalidation service is used.
598 // With external live servers, the profiles commit data on first sync cycle
599 // automatically after signing in. To avoid misleading sync commit
600 // notifications at start up, we start the SyncRefresher observers post
602 if (UsingExternalServers()) {
603 for (int i
= 0; i
< num_clients_
; ++i
) {
604 sync_refreshers_
[i
] = new P2PSyncRefresher(clients_
[i
]->service());
607 // OneClickSigninSyncStarter observer is created with a real user sign in.
608 // It is deleted on certain conditions which are not satisfied by our tests,
609 // and this causes the SigninTracker observer to stay hanging at shutdown.
610 // Calling LoginUIService::SyncConfirmationUIClosed forces the observer to
611 // be removed. http://crbug.com/484388
612 for (int i
= 0; i
< num_clients_
; ++i
) {
613 LoginUIServiceFactory::GetForProfile(GetProfile(i
))->
614 SyncConfirmationUIClosed(false /* configure_sync_first */);
621 void SyncTest::TearDownOnMainThread() {
622 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
623 clients_
[i
]->service()->RequestStop(ProfileSyncService::CLEAR_DATA
);
626 content::WindowedNotificationObserver
observer(
627 chrome::NOTIFICATION_BROWSER_CLOSED
,
628 content::NotificationService::AllSources());
629 chrome::CloseAllBrowsers();
631 // Waiting for a single notification mitigates flakiness (related to not all
632 // browsers being closed). If further flakiness is seen
633 // (GetTotalBrowserCount() > 0 after this call), GetTotalBrowserCount()
634 // notifications should be waited on.
637 if (fake_server_
.get()) {
638 std::vector
<fake_server::FakeServerInvalidationService
*>::const_iterator it
;
639 for (it
= fake_server_invalidation_services_
.begin();
640 it
!= fake_server_invalidation_services_
.end(); ++it
) {
641 fake_server_
->RemoveObserver(*it
);
645 // All browsers should be closed at this point, or else we could see memory
646 // corruption in QuitBrowser().
647 CHECK_EQ(0U, chrome::GetTotalBrowserCount());
648 invalidation_forwarders_
.clear();
649 sync_refreshers_
.clear();
650 fake_server_invalidation_services_
.clear();
654 void SyncTest::SetUpInProcessBrowserTestFixture() {
655 // We don't take a reference to |resolver|, but mock_host_resolver_override_
656 // does, so effectively assumes ownership.
657 net::RuleBasedHostResolverProc
* resolver
=
658 new net::RuleBasedHostResolverProc(host_resolver());
659 resolver
->AllowDirectLookup("*.google.com");
661 // Allow connection to googleapis.com for oauth token requests in E2E tests.
662 resolver
->AllowDirectLookup("*.googleapis.com");
664 // On Linux, we use Chromium's NSS implementation which uses the following
665 // hosts for certificate verification. Without these overrides, running the
666 // integration tests on Linux causes error as we make external DNS lookups.
667 resolver
->AllowDirectLookup("*.thawte.com");
668 resolver
->AllowDirectLookup("*.geotrust.com");
669 resolver
->AllowDirectLookup("*.gstatic.com");
670 mock_host_resolver_override_
.reset(
671 new net::ScopedDefaultHostResolverProc(resolver
));
674 void SyncTest::TearDownInProcessBrowserTestFixture() {
675 mock_host_resolver_override_
.reset();
678 void SyncTest::ReadPasswordFile() {
679 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
680 password_file_
= cl
->GetSwitchValuePath(switches::kPasswordFileForTest
);
681 if (password_file_
.empty())
682 LOG(FATAL
) << "Can't run live server test without specifying --"
683 << switches::kPasswordFileForTest
<< "=<filename>";
684 std::string file_contents
;
685 base::ReadFileToString(password_file_
, &file_contents
);
686 ASSERT_NE(file_contents
, "") << "Password file \""
687 << password_file_
.value() << "\" does not exist.";
688 std::vector
<std::string
> tokens
= base::SplitString(
689 file_contents
, "\r\n", base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
690 ASSERT_EQ(2U, tokens
.size()) << "Password file \""
691 << password_file_
.value()
692 << "\" must contain exactly two lines of text.";
693 username_
= tokens
[0];
694 password_
= tokens
[1];
697 void SyncTest::SetupMockGaiaResponses() {
698 factory_
.reset(new net::URLFetcherImplFactory());
699 fake_factory_
.reset(new net::FakeURLFetcherFactory(factory_
.get()));
700 fake_factory_
->SetFakeResponse(
701 GaiaUrls::GetInstance()->get_user_info_url(),
702 "email=user@gmail.com\ndisplayEmail=user@gmail.com",
704 net::URLRequestStatus::SUCCESS
);
705 fake_factory_
->SetFakeResponse(
706 GaiaUrls::GetInstance()->issue_auth_token_url(),
709 net::URLRequestStatus::SUCCESS
);
710 fake_factory_
->SetFakeResponse(
711 GURL(GoogleURLTracker::kSearchDomainCheckURL
),
714 net::URLRequestStatus::SUCCESS
);
715 fake_factory_
->SetFakeResponse(
716 GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
719 net::URLRequestStatus::SUCCESS
);
720 fake_factory_
->SetFakeResponse(
721 GaiaUrls::GetInstance()->oauth2_token_url(),
723 " \"refresh_token\": \"rt1\","
724 " \"access_token\": \"at1\","
725 " \"expires_in\": 3600,"
726 " \"token_type\": \"Bearer\""
729 net::URLRequestStatus::SUCCESS
);
730 fake_factory_
->SetFakeResponse(
731 GaiaUrls::GetInstance()->oauth_user_info_url(),
736 net::URLRequestStatus::SUCCESS
);
737 fake_factory_
->SetFakeResponse(
738 GaiaUrls::GetInstance()->oauth1_login_url(),
739 "SID=sid\nLSID=lsid\nAuth=auth_token",
741 net::URLRequestStatus::SUCCESS
);
742 fake_factory_
->SetFakeResponse(
743 GaiaUrls::GetInstance()->oauth2_revoke_url(),
746 net::URLRequestStatus::SUCCESS
);
749 void SyncTest::SetOAuth2TokenResponse(const std::string
& response_data
,
750 net::HttpStatusCode response_code
,
751 net::URLRequestStatus::Status status
) {
752 ASSERT_TRUE(NULL
!= fake_factory_
.get());
753 fake_factory_
->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
754 response_data
, response_code
, status
);
757 void SyncTest::ClearMockGaiaResponses() {
758 // Clear any mock gaia responses that might have been set.
760 fake_factory_
->ClearFakeResponses();
761 fake_factory_
.reset();
764 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
766 net::URLFetcher::CancelAll();
770 void SyncTest::DecideServerType() {
771 // Only set |server_type_| if it hasn't already been set. This allows for
772 // tests to explicitly set this value in each test class if needed.
773 if (server_type_
== SERVER_TYPE_UNDECIDED
) {
774 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
775 if (!cl
->HasSwitch(switches::kSyncServiceURL
) &&
776 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
777 // If neither a sync server URL nor a sync server command line is
778 // provided, start up a local sync test server and point Chrome
779 // to its URL. This is the most common configuration, and the only
780 // one that makes sense for most developers. FakeServer is the
781 // current solution but some scenarios are only supported by the
782 // legacy python server.
783 switch (test_type_
) {
786 case MULTIPLE_CLIENT
:
787 server_type_
= IN_PROCESS_FAKE_SERVER
;
790 server_type_
= LOCAL_PYTHON_SERVER
;
792 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
793 cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
794 // If a sync server URL and a sync server command line are provided,
795 // start up a local sync server by running the command line. Chrome
796 // will connect to the server at the URL that was provided.
797 server_type_
= LOCAL_LIVE_SERVER
;
798 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
799 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
800 // If a sync server URL is provided, but not a server command line,
801 // it is assumed that the server is already running. Chrome will
802 // automatically connect to it at the URL provided. There is nothing
804 server_type_
= EXTERNAL_LIVE_SERVER
;
806 // If a sync server command line is provided, but not a server URL,
808 LOG(FATAL
) << "Can't figure out how to run a server.";
813 // Start up a local sync server based on the value of server_type_, which
814 // was determined from the command line parameters.
815 void SyncTest::SetUpTestServerIfRequired() {
816 if (UsingExternalServers()) {
817 // Nothing to do; we'll just talk to the URL we were given.
818 } else if (server_type_
== LOCAL_PYTHON_SERVER
) {
819 if (!SetUpLocalPythonTestServer())
820 LOG(FATAL
) << "Failed to set up local python sync and XMPP servers";
821 SetupMockGaiaResponses();
822 } else if (server_type_
== LOCAL_LIVE_SERVER
) {
823 // Using mock gaia credentials requires the use of a mock XMPP server.
824 if (username_
== "user@gmail.com" && !SetUpLocalPythonTestServer())
825 LOG(FATAL
) << "Failed to set up local python XMPP server";
826 if (!SetUpLocalTestServer())
827 LOG(FATAL
) << "Failed to set up local test server";
828 } else if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
829 fake_server_
.reset(new fake_server::FakeServer());
830 SetupMockGaiaResponses();
832 LOG(FATAL
) << "Don't know which server environment to run test in.";
836 bool SyncTest::SetUpLocalPythonTestServer() {
837 EXPECT_TRUE(sync_server_
.Start())
838 << "Could not launch local python test server.";
840 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
841 if (server_type_
== LOCAL_PYTHON_SERVER
) {
842 std::string sync_service_url
= sync_server_
.GetURL("chromiumsync").spec();
843 cl
->AppendSwitchASCII(switches::kSyncServiceURL
, sync_service_url
);
844 DVLOG(1) << "Started local python sync server at " << sync_service_url
;
848 if (!sync_server_
.server_data().GetInteger("xmpp_port", &xmpp_port
)) {
849 LOG(ERROR
) << "Could not find valid xmpp_port value";
852 if ((xmpp_port
<= 0) || (xmpp_port
> kuint16max
)) {
853 LOG(ERROR
) << "Invalid xmpp port: " << xmpp_port
;
857 net::HostPortPair
xmpp_host_port_pair(sync_server_
.host_port_pair());
858 xmpp_host_port_pair
.set_port(xmpp_port
);
859 xmpp_port_
.reset(new net::ScopedPortException(xmpp_port
));
861 if (!cl
->HasSwitch(invalidation::switches::kSyncNotificationHostPort
)) {
862 cl
->AppendSwitchASCII(invalidation::switches::kSyncNotificationHostPort
,
863 xmpp_host_port_pair
.ToString());
864 // The local XMPP server only supports insecure connections.
865 cl
->AppendSwitch(invalidation::switches::kSyncAllowInsecureXmppConnection
);
867 DVLOG(1) << "Started local python XMPP server at "
868 << xmpp_host_port_pair
.ToString();
873 bool SyncTest::SetUpLocalTestServer() {
874 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
875 base::CommandLine::StringType server_cmdline_string
=
876 cl
->GetSwitchValueNative(switches::kSyncServerCommandLine
);
877 base::CommandLine::StringVector server_cmdline_vector
= base::SplitString(
878 server_cmdline_string
, FILE_PATH_LITERAL(" "),
879 base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
880 base::CommandLine
server_cmdline(server_cmdline_vector
);
881 base::LaunchOptions options
;
883 options
.start_hidden
= true;
885 test_server_
= base::LaunchProcess(server_cmdline
, options
);
886 if (!test_server_
.IsValid())
887 LOG(ERROR
) << "Could not launch local test server.";
889 const base::TimeDelta kMaxWaitTime
= TestTimeouts::action_max_timeout();
890 const int kNumIntervals
= 15;
891 if (WaitForTestServerToStart(kMaxWaitTime
, kNumIntervals
)) {
892 DVLOG(1) << "Started local test server at "
893 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
896 LOG(ERROR
) << "Could not start local test server at "
897 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
902 bool SyncTest::TearDownLocalPythonTestServer() {
903 if (!sync_server_
.Stop()) {
904 LOG(ERROR
) << "Could not stop local python test server.";
911 bool SyncTest::TearDownLocalTestServer() {
912 if (test_server_
.IsValid()) {
913 EXPECT_TRUE(test_server_
.Terminate(0, false))
914 << "Could not stop local test server.";
915 test_server_
.Close();
920 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait
, int intervals
) {
921 for (int i
= 0; i
< intervals
; ++i
) {
922 if (IsTestServerRunning())
924 base::PlatformThread::Sleep(wait
/ intervals
);
929 bool SyncTest::IsTestServerRunning() {
930 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
931 std::string sync_url
= cl
->GetSwitchValueASCII(switches::kSyncServiceURL
);
932 GURL
sync_url_status(sync_url
.append("/healthz"));
933 SyncServerStatusChecker delegate
;
934 scoped_ptr
<net::URLFetcher
> fetcher
=
935 net::URLFetcher::Create(sync_url_status
, net::URLFetcher::GET
, &delegate
);
936 fetcher
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
937 net::LOAD_DO_NOT_SEND_COOKIES
|
938 net::LOAD_DO_NOT_SAVE_COOKIES
);
939 fetcher
->SetRequestContext(g_browser_process
->system_request_context());
941 content::RunMessageLoop();
942 return delegate
.running();
945 bool SyncTest::TestUsesSelfNotifications() {
949 bool SyncTest::EnableEncryption(int index
) {
950 ProfileSyncService
* service
= GetClient(index
)->service();
952 if (::IsEncryptionComplete(service
))
955 service
->EnableEncryptEverything();
957 // In order to kick off the encryption we have to reconfigure. Just grab the
958 // currently synced types and use them.
959 const syncer::ModelTypeSet synced_datatypes
=
960 service
->GetPreferredDataTypes();
961 bool sync_everything
= synced_datatypes
.Equals(syncer::ModelTypeSet::All());
962 service
->OnUserChoseDatatypes(sync_everything
, synced_datatypes
);
964 return AwaitEncryptionComplete(index
);
967 bool SyncTest::IsEncryptionComplete(int index
) {
968 return ::IsEncryptionComplete(GetClient(index
)->service());
971 bool SyncTest::AwaitEncryptionComplete(int index
) {
972 ProfileSyncService
* service
= GetClient(index
)->service();
973 EncryptionChecker
checker(service
);
975 return !checker
.TimedOut();
978 bool SyncTest::AwaitQuiescence() {
979 return ProfileSyncServiceHarness::AwaitQuiescence(clients());
982 bool SyncTest::UsingExternalServers() {
983 return server_type_
== EXTERNAL_LIVE_SERVER
;
986 bool SyncTest::ServerSupportsNotificationControl() const {
987 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
989 // Supported only if we're using the python testserver.
990 return server_type_
== LOCAL_PYTHON_SERVER
;
993 void SyncTest::DisableNotificationsImpl() {
994 ASSERT_TRUE(ServerSupportsNotificationControl());
995 std::string path
= "chromiumsync/disablenotifications";
996 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
997 ASSERT_EQ("Notifications disabled",
999 browser()->tab_strip_model()->GetActiveWebContents()->
1003 void SyncTest::DisableNotifications() {
1004 DisableNotificationsImpl();
1005 notifications_enabled_
= false;
1008 void SyncTest::EnableNotificationsImpl() {
1009 ASSERT_TRUE(ServerSupportsNotificationControl());
1010 std::string path
= "chromiumsync/enablenotifications";
1011 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1012 ASSERT_EQ("Notifications enabled",
1014 browser()->tab_strip_model()->GetActiveWebContents()->
1018 void SyncTest::EnableNotifications() {
1019 EnableNotificationsImpl();
1020 notifications_enabled_
= true;
1023 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types
) {
1024 ASSERT_TRUE(ServerSupportsNotificationControl());
1025 const std::string
& data
=
1026 syncer::P2PNotificationData(
1029 syncer::ObjectIdInvalidationMap::InvalidateAll(
1030 syncer::ModelTypeSetToObjectIdSet(changed_types
))).ToString();
1031 const std::string
& path
=
1032 std::string("chromiumsync/sendnotification?channel=") +
1033 syncer::kSyncP2PNotificationChannel
+ "&data=" + data
;
1034 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1035 ASSERT_EQ("Notification sent",
1037 browser()->tab_strip_model()->GetActiveWebContents()->
1041 bool SyncTest::ServerSupportsErrorTriggering() const {
1042 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
1044 // Supported only if we're using the python testserver.
1045 return server_type_
== LOCAL_PYTHON_SERVER
;
1048 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types
) {
1049 ASSERT_TRUE(ServerSupportsErrorTriggering());
1050 std::string path
= "chromiumsync/migrate";
1052 for (syncer::ModelTypeSet::Iterator it
= model_types
.First();
1053 it
.Good(); it
.Inc()) {
1056 "%ctype=%d", joiner
,
1057 syncer::GetSpecificsFieldNumberFromModelType(it
.Get())));
1060 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1061 ASSERT_EQ("Migration: 200",
1063 browser()->tab_strip_model()->GetActiveWebContents()->
1067 void SyncTest::TriggerXmppAuthError() {
1068 ASSERT_TRUE(ServerSupportsErrorTriggering());
1069 std::string path
= "chromiumsync/xmppcred";
1070 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1073 void SyncTest::TriggerCreateSyncedBookmarks() {
1074 ASSERT_TRUE(ServerSupportsErrorTriggering());
1075 std::string path
= "chromiumsync/createsyncedbookmarks";
1076 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
1077 ASSERT_EQ("Synced Bookmarks",
1079 browser()->tab_strip_model()->GetActiveWebContents()->
1083 void SyncTest::SetupNetwork(net::URLRequestContextGetter
* context_getter
) {
1084 base::WaitableEvent
done(false, false);
1085 BrowserThread::PostTask(
1086 BrowserThread::IO
, FROM_HERE
,
1087 base::Bind(&SetupNetworkCallback
, &done
,
1088 make_scoped_refptr(context_getter
)));
1092 fake_server::FakeServer
* SyncTest::GetFakeServer() const {
1093 return fake_server_
.get();
1096 void SyncTest::TriggerSyncForModelTypes(int index
,
1097 syncer::ModelTypeSet model_types
) {
1098 content::NotificationService::current()->Notify(
1099 chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
,
1100 content::Source
<Profile
>(GetProfile(index
)),
1101 content::Details
<const syncer::ModelTypeSet
>(&model_types
));
1104 void SyncTest::SetPreexistingPreferencesFileContents(
1105 const std::string
& contents
) {
1106 preexisting_preferences_file_contents_
= contents
;