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/lifetime/application_lifetime.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/profiles/profile_manager.h"
31 #include "chrome/browser/search_engines/template_url_service.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/browser/sync/profile_sync_service_factory.h"
34 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
35 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_finder.h"
38 #include "chrome/browser/ui/host_desktop.h"
39 #include "chrome/browser/ui/tabs/tab_strip_model.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/chrome_switches.h"
42 #include "chrome/test/base/testing_browser_process.h"
43 #include "chrome/test/base/ui_test_utils.h"
44 #include "components/webdata/encryptor/encryptor.h"
45 #include "content/public/browser/web_contents.h"
46 #include "content/public/test/test_browser_thread.h"
47 #include "google_apis/gaia/gaia_urls.h"
48 #include "net/base/escape.h"
49 #include "net/base/load_flags.h"
50 #include "net/base/network_change_notifier.h"
51 #include "net/proxy/proxy_config.h"
52 #include "net/proxy/proxy_config_service_fixed.h"
53 #include "net/proxy/proxy_service.h"
54 #include "net/test/spawned_test_server/spawned_test_server.h"
55 #include "net/url_request/test_url_fetcher_factory.h"
56 #include "net/url_request/url_fetcher.h"
57 #include "net/url_request/url_fetcher_delegate.h"
58 #include "net/url_request/url_request_context.h"
59 #include "net/url_request/url_request_context_getter.h"
60 #include "sync/engine/sync_scheduler_impl.h"
61 #include "sync/notifier/p2p_invalidator.h"
62 #include "sync/protocol/sync.pb.h"
63 #include "sync/test/fake_server/fake_server.h"
64 #include "sync/test/fake_server/fake_server_network_resources.h"
67 using content::BrowserThread
;
68 using invalidation::InvalidationServiceFactory
;
71 const char kPasswordFileForTest
[] = "password-file-for-test";
72 const char kSyncUserForTest
[] = "sync-user-for-test";
73 const char kSyncPasswordForTest
[] = "sync-password-for-test";
74 const char kSyncServerCommandLine
[] = "sync-server-command-line";
77 // Helper class that checks whether a sync test server is running or not.
78 class SyncServerStatusChecker
: public net::URLFetcherDelegate
{
80 SyncServerStatusChecker() : running_(false) {}
82 virtual void OnURLFetchComplete(const net::URLFetcher
* source
) OVERRIDE
{
84 source
->GetResponseAsString(&data
);
86 (source
->GetStatus().status() == net::URLRequestStatus::SUCCESS
&&
87 source
->GetResponseCode() == 200 && data
.find("ok") == 0);
88 base::MessageLoop::current()->Quit();
91 bool running() const { return running_
; }
97 void SetProxyConfigCallback(
98 base::WaitableEvent
* done
,
99 net::URLRequestContextGetter
* url_request_context_getter
,
100 const net::ProxyConfig
& proxy_config
) {
101 net::ProxyService
* proxy_service
=
102 url_request_context_getter
->GetURLRequestContext()->proxy_service();
103 proxy_service
->ResetConfigService(
104 new net::ProxyConfigServiceFixed(proxy_config
));
108 SyncTest::SyncTest(TestType test_type
)
109 : test_type_(test_type
),
110 server_type_(SERVER_TYPE_UNDECIDED
),
113 notifications_enabled_(true),
114 test_server_handle_(base::kNullProcessHandle
),
115 number_of_default_sync_items_(0) {
116 sync_datatype_helper::AssociateWithTest(this);
117 switch (test_type_
) {
118 case SINGLE_CLIENT
: {
126 case MULTIPLE_CLIENT
: {
133 SyncTest::~SyncTest() {}
135 void SyncTest::SetUp() {
136 CommandLine
* cl
= CommandLine::ForCurrentProcess();
137 if (cl
->HasSwitch(switches::kPasswordFileForTest
)) {
139 } else if (cl
->HasSwitch(switches::kSyncUserForTest
) &&
140 cl
->HasSwitch(switches::kSyncPasswordForTest
)) {
141 username_
= cl
->GetSwitchValueASCII(switches::kSyncUserForTest
);
142 password_
= cl
->GetSwitchValueASCII(switches::kSyncPasswordForTest
);
144 username_
= "user@gmail.com";
145 password_
= "password";
148 // Only set |server_type_| if it hasn't already been set. This allows for
149 // IN_PROCESS_FAKE_SERVER tests to set this value in each test class.
150 if (server_type_
== SERVER_TYPE_UNDECIDED
) {
151 if (!cl
->HasSwitch(switches::kSyncServiceURL
) &&
152 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
153 // If neither a sync server URL nor a sync server command line is
154 // provided, start up a local python sync test server and point Chrome
155 // to its URL. This is the most common configuration, and the only
156 // one that makes sense for most developers.
157 server_type_
= LOCAL_PYTHON_SERVER
;
158 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
159 cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
160 // If a sync server URL and a sync server command line are provided,
161 // start up a local sync server by running the command line. Chrome
162 // will connect to the server at the URL that was provided.
163 server_type_
= LOCAL_LIVE_SERVER
;
164 } else if (cl
->HasSwitch(switches::kSyncServiceURL
) &&
165 !cl
->HasSwitch(switches::kSyncServerCommandLine
)) {
166 // If a sync server URL is provided, but not a server command line,
167 // it is assumed that the server is already running. Chrome will
168 // automatically connect to it at the URL provided. There is nothing
170 server_type_
= EXTERNAL_LIVE_SERVER
;
172 // If a sync server command line is provided, but not a server URL,
174 LOG(FATAL
) << "Can't figure out how to run a server.";
178 if (username_
.empty() || password_
.empty())
179 LOG(FATAL
) << "Cannot run sync tests without GAIA credentials.";
181 // Mock the Mac Keychain service. The real Keychain can block on user input.
182 #if defined(OS_MACOSX)
183 Encryptor::UseMockKeychain(true);
186 // Start up a sync test server if one is needed and setup mock gaia responses.
187 // Note: This must be done prior to the call to SetupClients() because we want
188 // the mock gaia responses to be available before GaiaUrls is initialized.
189 SetUpTestServerIfRequired();
191 // Yield control back to the InProcessBrowserTest framework.
192 InProcessBrowserTest::SetUp();
195 void SyncTest::TearDown() {
196 // Clear any mock gaia responses that might have been set.
197 ClearMockGaiaResponses();
199 // Allow the InProcessBrowserTest framework to perform its tear down.
200 InProcessBrowserTest::TearDown();
202 // Stop the local python test server. This is a no-op if one wasn't started.
203 TearDownLocalPythonTestServer();
205 // Stop the local sync test server. This is a no-op if one wasn't started.
206 TearDownLocalTestServer();
209 void SyncTest::SetUpCommandLine(CommandLine
* cl
) {
211 AddOptionalTypesToCommandLine(cl
);
214 void SyncTest::AddTestSwitches(CommandLine
* cl
) {
215 // Disable non-essential access of external network resources.
216 if (!cl
->HasSwitch(switches::kDisableBackgroundNetworking
))
217 cl
->AppendSwitch(switches::kDisableBackgroundNetworking
);
219 if (!cl
->HasSwitch(switches::kSyncShortInitialRetryOverride
))
220 cl
->AppendSwitch(switches::kSyncShortInitialRetryOverride
);
222 // TODO(sync): Fix enable_disable_test.cc to play nice with priority
224 if (!cl
->HasSwitch(switches::kDisableSyncPriorityPreferences
))
225 cl
->AppendSwitch(switches::kDisableSyncPriorityPreferences
);
228 void SyncTest::AddOptionalTypesToCommandLine(CommandLine
* cl
) {}
231 Profile
* SyncTest::MakeProfile(const base::FilePath::StringType name
) {
233 PathService::Get(chrome::DIR_USER_DATA
, &path
);
234 path
= path
.Append(name
);
236 if (!base::PathExists(path
))
237 CHECK(base::CreateDirectory(path
));
240 Profile::CreateProfile(path
, NULL
, Profile::CREATE_MODE_SYNCHRONOUS
);
241 g_browser_process
->profile_manager()->RegisterTestingProfile(profile
,
247 Profile
* SyncTest::GetProfile(int index
) {
248 if (profiles_
.empty())
249 LOG(FATAL
) << "SetupClients() has not yet been called.";
250 if (index
< 0 || index
>= static_cast<int>(profiles_
.size()))
251 LOG(FATAL
) << "GetProfile(): Index is out of bounds.";
252 return profiles_
[index
];
255 Browser
* SyncTest::GetBrowser(int index
) {
256 if (browsers_
.empty())
257 LOG(FATAL
) << "SetupClients() has not yet been called.";
258 if (index
< 0 || index
>= static_cast<int>(browsers_
.size()))
259 LOG(FATAL
) << "GetBrowser(): Index is out of bounds.";
260 return browsers_
[index
];
263 ProfileSyncServiceHarness
* SyncTest::GetClient(int index
) {
264 if (clients_
.empty())
265 LOG(FATAL
) << "SetupClients() has not yet been called.";
266 if (index
< 0 || index
>= static_cast<int>(clients_
.size()))
267 LOG(FATAL
) << "GetClient(): Index is out of bounds.";
268 return clients_
[index
];
271 Profile
* SyncTest::verifier() {
272 if (verifier_
== NULL
)
273 LOG(FATAL
) << "SetupClients() has not yet been called.";
277 void SyncTest::DisableVerifier() {
278 use_verifier_
= false;
281 bool SyncTest::SetupClients() {
282 if (num_clients_
<= 0)
283 LOG(FATAL
) << "num_clients_ incorrectly initialized.";
284 if (!profiles_
.empty() || !browsers_
.empty() || !clients_
.empty())
285 LOG(FATAL
) << "SetupClients() has already been called.";
287 // Create the required number of sync profiles, browsers and clients.
288 profiles_
.resize(num_clients_
);
289 browsers_
.resize(num_clients_
);
290 clients_
.resize(num_clients_
);
291 for (int i
= 0; i
< num_clients_
; ++i
) {
292 InitializeInstance(i
);
295 // Create the verifier profile.
296 verifier_
= MakeProfile(FILE_PATH_LITERAL("Verifier"));
297 test::WaitForBookmarkModelToLoad(
298 BookmarkModelFactory::GetForProfile(verifier()));
299 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
300 verifier(), Profile::EXPLICIT_ACCESS
));
301 ui_test_utils::WaitForTemplateURLServiceToLoad(
302 TemplateURLServiceFactory::GetForProfile(verifier()));
303 return (verifier_
!= NULL
);
306 void SyncTest::InitializeInstance(int index
) {
307 profiles_
[index
] = MakeProfile(
308 base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index
));
309 EXPECT_FALSE(GetProfile(index
) == NULL
) << "Could not create Profile "
312 browsers_
[index
] = new Browser(Browser::CreateParams(
313 GetProfile(index
), chrome::GetActiveDesktop()));
314 EXPECT_FALSE(GetBrowser(index
) == NULL
) << "Could not create Browser "
317 invalidation::P2PInvalidationService
* p2p_invalidation_service
=
318 InvalidationServiceFactory::GetInstance()->
319 BuildAndUseP2PInvalidationServiceForTest(GetProfile(index
));
320 p2p_invalidation_service
->UpdateCredentials(username_
, password_
);
322 // Make sure the ProfileSyncService has been created before creating the
323 // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
325 ProfileSyncService
* profile_sync_service
=
326 ProfileSyncServiceFactory::GetForProfile(GetProfile(index
));
328 if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
329 // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
330 profile_sync_service
->OverrideNetworkResourcesForTest(
331 make_scoped_ptr
<syncer::NetworkResources
>(
332 new syncer::FakeServerNetworkResources(fake_server_
.get())));
336 ProfileSyncServiceHarness::CreateForIntegrationTest(
340 p2p_invalidation_service
);
341 EXPECT_FALSE(GetClient(index
) == NULL
) << "Could not create Client "
344 test::WaitForBookmarkModelToLoad(
345 BookmarkModelFactory::GetForProfile(GetProfile(index
)));
346 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
347 GetProfile(index
), Profile::EXPLICIT_ACCESS
));
348 ui_test_utils::WaitForTemplateURLServiceToLoad(
349 TemplateURLServiceFactory::GetForProfile(GetProfile(index
)));
352 bool SyncTest::SetupSync() {
353 // Create sync profiles and clients if they haven't already been created.
354 if (profiles_
.empty()) {
356 LOG(FATAL
) << "SetupClients() failed.";
359 // Sync each of the profiles.
360 for (int i
= 0; i
< num_clients_
; ++i
) {
361 if (!GetClient(i
)->SetupSync())
362 LOG(FATAL
) << "SetupSync() failed.";
365 // Because clients may modify sync data as part of startup (for example local
366 // session-releated data is rewritten), we need to ensure all startup-based
367 // changes have propagated between the clients.
370 // The number of default entries is the number of entries existing after
371 // sync startup excluding top level folders and other permanent items.
372 // This value must be updated whenever new permanent items are added (although
373 // this should handle new datatype-specific top level folders).
374 number_of_default_sync_items_
= GetClient(0)->GetNumEntries() -
375 GetClient(0)->GetNumDatatypes() - 6;
376 DVLOG(1) << "Setting " << number_of_default_sync_items_
<< " as default "
377 << " number of entries.";
382 void SyncTest::CleanUpOnMainThread() {
383 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
384 clients_
[i
]->service()->DisableForUser();
387 // Some of the pending messages might rely on browser windows still being
388 // around, so run messages both before and after closing all browsers.
389 content::RunAllPendingInMessageLoop();
390 // Close all browser windows.
391 chrome::CloseAllBrowsers();
392 content::RunAllPendingInMessageLoop();
394 // All browsers should be closed at this point, or else we could see memory
395 // corruption in QuitBrowser().
396 CHECK_EQ(0U, chrome::GetTotalBrowserCount());
400 void SyncTest::SetUpInProcessBrowserTestFixture() {
401 // We don't take a reference to |resolver|, but mock_host_resolver_override_
402 // does, so effectively assumes ownership.
403 net::RuleBasedHostResolverProc
* resolver
=
404 new net::RuleBasedHostResolverProc(host_resolver());
405 resolver
->AllowDirectLookup("*.google.com");
406 // On Linux, we use Chromium's NSS implementation which uses the following
407 // hosts for certificate verification. Without these overrides, running the
408 // integration tests on Linux causes error as we make external DNS lookups.
409 resolver
->AllowDirectLookup("*.thawte.com");
410 resolver
->AllowDirectLookup("*.geotrust.com");
411 resolver
->AllowDirectLookup("*.gstatic.com");
412 mock_host_resolver_override_
.reset(
413 new net::ScopedDefaultHostResolverProc(resolver
));
416 void SyncTest::TearDownInProcessBrowserTestFixture() {
417 mock_host_resolver_override_
.reset();
420 void SyncTest::ReadPasswordFile() {
421 CommandLine
* cl
= CommandLine::ForCurrentProcess();
422 password_file_
= cl
->GetSwitchValuePath(switches::kPasswordFileForTest
);
423 if (password_file_
.empty())
424 LOG(FATAL
) << "Can't run live server test without specifying --"
425 << switches::kPasswordFileForTest
<< "=<filename>";
426 std::string file_contents
;
427 base::ReadFileToString(password_file_
, &file_contents
);
428 ASSERT_NE(file_contents
, "") << "Password file \""
429 << password_file_
.value() << "\" does not exist.";
430 std::vector
<std::string
> tokens
;
431 std::string delimiters
= "\r\n";
432 Tokenize(file_contents
, delimiters
, &tokens
);
433 ASSERT_EQ(2U, tokens
.size()) << "Password file \""
434 << password_file_
.value()
435 << "\" must contain exactly two lines of text.";
436 username_
= tokens
[0];
437 password_
= tokens
[1];
440 void SyncTest::SetupMockGaiaResponses() {
441 factory_
.reset(new net::URLFetcherImplFactory());
442 fake_factory_
.reset(new net::FakeURLFetcherFactory(factory_
.get()));
443 fake_factory_
->SetFakeResponse(
444 GaiaUrls::GetInstance()->get_user_info_url(),
445 "email=user@gmail.com\ndisplayEmail=user@gmail.com",
447 net::URLRequestStatus::SUCCESS
);
448 fake_factory_
->SetFakeResponse(
449 GaiaUrls::GetInstance()->issue_auth_token_url(),
452 net::URLRequestStatus::SUCCESS
);
453 fake_factory_
->SetFakeResponse(
454 GURL(GoogleURLTracker::kSearchDomainCheckURL
),
457 net::URLRequestStatus::SUCCESS
);
458 fake_factory_
->SetFakeResponse(
459 GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
462 net::URLRequestStatus::SUCCESS
);
463 fake_factory_
->SetFakeResponse(
464 GaiaUrls::GetInstance()->oauth2_token_url(),
466 " \"refresh_token\": \"rt1\","
467 " \"access_token\": \"at1\","
468 " \"expires_in\": 3600,"
469 " \"token_type\": \"Bearer\""
472 net::URLRequestStatus::SUCCESS
);
473 fake_factory_
->SetFakeResponse(
474 GaiaUrls::GetInstance()->oauth_user_info_url(),
479 net::URLRequestStatus::SUCCESS
);
480 fake_factory_
->SetFakeResponse(
481 GaiaUrls::GetInstance()->oauth1_login_url(),
482 "SID=sid\nLSID=lsid\nAuth=auth_token",
484 net::URLRequestStatus::SUCCESS
);
485 fake_factory_
->SetFakeResponse(
486 GaiaUrls::GetInstance()->oauth2_revoke_url(),
489 net::URLRequestStatus::SUCCESS
);
492 void SyncTest::SetOAuth2TokenResponse(const std::string
& response_data
,
493 net::HttpStatusCode response_code
,
494 net::URLRequestStatus::Status status
) {
495 ASSERT_TRUE(NULL
!= fake_factory_
.get());
496 fake_factory_
->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
497 response_data
, response_code
, status
);
500 void SyncTest::ClearMockGaiaResponses() {
501 // Clear any mock gaia responses that might have been set.
503 fake_factory_
->ClearFakeResponses();
504 fake_factory_
.reset();
507 // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
509 net::URLFetcher::CancelAll();
513 // Start up a local sync server based on the value of server_type_, which
514 // was determined from the command line parameters.
515 void SyncTest::SetUpTestServerIfRequired() {
516 if (server_type_
== LOCAL_PYTHON_SERVER
) {
517 if (!SetUpLocalPythonTestServer())
518 LOG(FATAL
) << "Failed to set up local python sync and XMPP servers";
519 SetupMockGaiaResponses();
520 } else if (server_type_
== LOCAL_LIVE_SERVER
) {
521 // Using mock gaia credentials requires the use of a mock XMPP server.
522 if (username_
== "user@gmail.com" && !SetUpLocalPythonTestServer())
523 LOG(FATAL
) << "Failed to set up local python XMPP server";
524 if (!SetUpLocalTestServer())
525 LOG(FATAL
) << "Failed to set up local test server";
526 } else if (server_type_
== IN_PROCESS_FAKE_SERVER
) {
527 fake_server_
.reset(new syncer::FakeServer());
528 // Similar to LOCAL_LIVE_SERVER, we must start this for XMPP.
529 SetUpLocalPythonTestServer();
530 SetupMockGaiaResponses();
531 } else if (server_type_
== EXTERNAL_LIVE_SERVER
) {
532 // Nothing to do; we'll just talk to the URL we were given.
534 LOG(FATAL
) << "Don't know which server environment to run test in.";
538 bool SyncTest::SetUpLocalPythonTestServer() {
539 EXPECT_TRUE(sync_server_
.Start())
540 << "Could not launch local python test server.";
542 CommandLine
* cl
= CommandLine::ForCurrentProcess();
543 if (server_type_
== LOCAL_PYTHON_SERVER
) {
544 std::string sync_service_url
= sync_server_
.GetURL("chromiumsync").spec();
545 cl
->AppendSwitchASCII(switches::kSyncServiceURL
, sync_service_url
);
546 DVLOG(1) << "Started local python sync server at " << sync_service_url
;
550 if (!sync_server_
.server_data().GetInteger("xmpp_port", &xmpp_port
)) {
551 LOG(ERROR
) << "Could not find valid xmpp_port value";
554 if ((xmpp_port
<= 0) || (xmpp_port
> kuint16max
)) {
555 LOG(ERROR
) << "Invalid xmpp port: " << xmpp_port
;
559 net::HostPortPair
xmpp_host_port_pair(sync_server_
.host_port_pair());
560 xmpp_host_port_pair
.set_port(xmpp_port
);
561 xmpp_port_
.reset(new net::ScopedPortException(xmpp_port
));
563 if (!cl
->HasSwitch(switches::kSyncNotificationHostPort
)) {
564 cl
->AppendSwitchASCII(switches::kSyncNotificationHostPort
,
565 xmpp_host_port_pair
.ToString());
566 // The local XMPP server only supports insecure connections.
567 cl
->AppendSwitch(switches::kSyncAllowInsecureXmppConnection
);
569 DVLOG(1) << "Started local python XMPP server at "
570 << xmpp_host_port_pair
.ToString();
575 bool SyncTest::SetUpLocalTestServer() {
576 CommandLine
* cl
= CommandLine::ForCurrentProcess();
577 CommandLine::StringType server_cmdline_string
= cl
->GetSwitchValueNative(
578 switches::kSyncServerCommandLine
);
579 CommandLine::StringVector server_cmdline_vector
;
580 CommandLine::StringType
delimiters(FILE_PATH_LITERAL(" "));
581 Tokenize(server_cmdline_string
, delimiters
, &server_cmdline_vector
);
582 CommandLine
server_cmdline(server_cmdline_vector
);
583 base::LaunchOptions options
;
585 options
.start_hidden
= true;
587 if (!base::LaunchProcess(server_cmdline
, options
, &test_server_handle_
))
588 LOG(ERROR
) << "Could not launch local test server.";
590 const base::TimeDelta kMaxWaitTime
= TestTimeouts::action_max_timeout();
591 const int kNumIntervals
= 15;
592 if (WaitForTestServerToStart(kMaxWaitTime
, kNumIntervals
)) {
593 DVLOG(1) << "Started local test server at "
594 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
597 LOG(ERROR
) << "Could not start local test server at "
598 << cl
->GetSwitchValueASCII(switches::kSyncServiceURL
) << ".";
603 bool SyncTest::TearDownLocalPythonTestServer() {
604 if (!sync_server_
.Stop()) {
605 LOG(ERROR
) << "Could not stop local python test server.";
612 bool SyncTest::TearDownLocalTestServer() {
613 if (test_server_handle_
!= base::kNullProcessHandle
) {
614 EXPECT_TRUE(base::KillProcess(test_server_handle_
, 0, false))
615 << "Could not stop local test server.";
616 base::CloseProcessHandle(test_server_handle_
);
617 test_server_handle_
= base::kNullProcessHandle
;
622 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait
, int intervals
) {
623 for (int i
= 0; i
< intervals
; ++i
) {
624 if (IsTestServerRunning())
626 base::PlatformThread::Sleep(wait
/ intervals
);
631 bool SyncTest::IsTestServerRunning() {
632 CommandLine
* cl
= CommandLine::ForCurrentProcess();
633 std::string sync_url
= cl
->GetSwitchValueASCII(switches::kSyncServiceURL
);
634 GURL
sync_url_status(sync_url
.append("/healthz"));
635 SyncServerStatusChecker delegate
;
636 scoped_ptr
<net::URLFetcher
> fetcher(net::URLFetcher::Create(
637 sync_url_status
, net::URLFetcher::GET
, &delegate
));
638 fetcher
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
639 net::LOAD_DO_NOT_SEND_COOKIES
|
640 net::LOAD_DO_NOT_SAVE_COOKIES
);
641 fetcher
->SetRequestContext(g_browser_process
->system_request_context());
643 content::RunMessageLoop();
644 return delegate
.running();
647 void SyncTest::EnableNetwork(Profile
* profile
) {
648 SetProxyConfig(profile
->GetRequestContext(),
649 net::ProxyConfig::CreateDirect());
650 if (notifications_enabled_
) {
651 EnableNotificationsImpl();
653 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
654 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
657 void SyncTest::DisableNetwork(Profile
* profile
) {
658 DisableNotificationsImpl();
659 // Set the current proxy configuration to a nonexistent proxy to effectively
660 // disable networking.
661 net::ProxyConfig config
;
662 config
.proxy_rules().ParseFromString("http=127.0.0.1:0");
663 SetProxyConfig(profile
->GetRequestContext(), config
);
664 // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
665 net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
668 bool SyncTest::EnableEncryption(int index
) {
669 return GetClient(index
)->EnableEncryption();
672 bool SyncTest::IsEncryptionComplete(int index
) {
673 return GetClient(index
)->IsEncryptionComplete();
676 bool SyncTest::AwaitQuiescence() {
677 return ProfileSyncServiceHarness::AwaitQuiescence(clients());
680 bool SyncTest::ServerSupportsNotificationControl() const {
681 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
683 // Supported only if we're using the python testserver.
684 return server_type_
== LOCAL_PYTHON_SERVER
;
687 void SyncTest::DisableNotificationsImpl() {
688 ASSERT_TRUE(ServerSupportsNotificationControl());
689 std::string path
= "chromiumsync/disablenotifications";
690 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
691 ASSERT_EQ("Notifications disabled",
692 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
696 void SyncTest::DisableNotifications() {
697 DisableNotificationsImpl();
698 notifications_enabled_
= false;
701 void SyncTest::EnableNotificationsImpl() {
702 ASSERT_TRUE(ServerSupportsNotificationControl());
703 std::string path
= "chromiumsync/enablenotifications";
704 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
705 ASSERT_EQ("Notifications enabled",
706 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
710 void SyncTest::EnableNotifications() {
711 EnableNotificationsImpl();
712 notifications_enabled_
= true;
715 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types
) {
716 ASSERT_TRUE(ServerSupportsNotificationControl());
717 const std::string
& data
=
718 syncer::P2PNotificationData(
721 syncer::ObjectIdInvalidationMap::InvalidateAll(
722 syncer::ModelTypeSetToObjectIdSet(changed_types
))).ToString();
723 const std::string
& path
=
724 std::string("chromiumsync/sendnotification?channel=") +
725 syncer::kSyncP2PNotificationChannel
+ "&data=" + data
;
726 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
727 ASSERT_EQ("Notification sent",
728 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
732 bool SyncTest::ServerSupportsErrorTriggering() const {
733 EXPECT_NE(SERVER_TYPE_UNDECIDED
, server_type_
);
735 // Supported only if we're using the python testserver.
736 return server_type_
== LOCAL_PYTHON_SERVER
;
739 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types
) {
740 ASSERT_TRUE(ServerSupportsErrorTriggering());
741 std::string path
= "chromiumsync/migrate";
743 for (syncer::ModelTypeSet::Iterator it
= model_types
.First();
744 it
.Good(); it
.Inc()) {
748 syncer::GetSpecificsFieldNumberFromModelType(it
.Get())));
751 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
752 ASSERT_EQ("Migration: 200",
753 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
757 void SyncTest::TriggerBirthdayError() {
758 ASSERT_TRUE(ServerSupportsErrorTriggering());
759 std::string path
= "chromiumsync/birthdayerror";
760 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
761 ASSERT_EQ("Birthday error",
762 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
766 void SyncTest::TriggerTransientError() {
767 ASSERT_TRUE(ServerSupportsErrorTriggering());
768 std::string path
= "chromiumsync/transienterror";
769 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
770 ASSERT_EQ("Transient error",
771 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
775 void SyncTest::TriggerAuthState(PythonServerAuthState auth_state
) {
776 ASSERT_TRUE(ServerSupportsErrorTriggering());
777 std::string path
= "chromiumsync/cred";
778 path
.append(auth_state
== AUTHENTICATED_TRUE
? "?valid=True" :
780 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
783 void SyncTest::TriggerXmppAuthError() {
784 ASSERT_TRUE(ServerSupportsErrorTriggering());
785 std::string path
= "chromiumsync/xmppcred";
786 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
791 sync_pb::SyncEnums::ErrorType
792 GetClientToServerResponseErrorType(
793 syncer::SyncProtocolErrorType error
) {
795 case syncer::SYNC_SUCCESS
:
796 return sync_pb::SyncEnums::SUCCESS
;
797 case syncer::NOT_MY_BIRTHDAY
:
798 return sync_pb::SyncEnums::NOT_MY_BIRTHDAY
;
799 case syncer::THROTTLED
:
800 return sync_pb::SyncEnums::THROTTLED
;
801 case syncer::CLEAR_PENDING
:
802 return sync_pb::SyncEnums::CLEAR_PENDING
;
803 case syncer::TRANSIENT_ERROR
:
804 return sync_pb::SyncEnums::TRANSIENT_ERROR
;
805 case syncer::MIGRATION_DONE
:
806 return sync_pb::SyncEnums::MIGRATION_DONE
;
807 case syncer::UNKNOWN_ERROR
:
808 return sync_pb::SyncEnums::UNKNOWN
;
811 return sync_pb::SyncEnums::UNKNOWN
;
815 sync_pb::SyncEnums::Action
GetClientToServerResponseAction(
816 const syncer::ClientAction
& action
) {
818 case syncer::UPGRADE_CLIENT
:
819 return sync_pb::SyncEnums::UPGRADE_CLIENT
;
820 case syncer::CLEAR_USER_DATA_AND_RESYNC
:
821 return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC
;
822 case syncer::ENABLE_SYNC_ON_ACCOUNT
:
823 return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT
;
824 case syncer::STOP_AND_RESTART_SYNC
:
825 return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC
;
826 case syncer::DISABLE_SYNC_ON_CLIENT
:
827 return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT
;
828 case syncer::UNKNOWN_ACTION
:
829 return sync_pb::SyncEnums::UNKNOWN_ACTION
;
832 return sync_pb::SyncEnums::UNKNOWN_ACTION
;
838 void SyncTest::TriggerSyncError(const syncer::SyncProtocolError
& error
,
839 SyncErrorFrequency frequency
) {
840 ASSERT_TRUE(ServerSupportsErrorTriggering());
841 std::string path
= "chromiumsync/error";
843 static_cast<int>(GetClientToServerResponseErrorType(
845 int action
= static_cast<int>(GetClientToServerResponseAction(
848 path
.append(base::StringPrintf("?error=%d", error_type
));
849 path
.append(base::StringPrintf("&action=%d", action
));
851 path
.append(base::StringPrintf("&error_description=%s",
852 error
.error_description
.c_str()));
853 path
.append(base::StringPrintf("&url=%s", error
.url
.c_str()));
854 path
.append(base::StringPrintf("&frequency=%d", frequency
));
856 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
857 std::string output
= UTF16ToASCII(
858 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
859 ASSERT_TRUE(output
.find("SetError: 200") != base::string16::npos
);
862 void SyncTest::TriggerCreateSyncedBookmarks() {
863 ASSERT_TRUE(ServerSupportsErrorTriggering());
864 std::string path
= "chromiumsync/createsyncedbookmarks";
865 ui_test_utils::NavigateToURL(browser(), sync_server_
.GetURL(path
));
866 ASSERT_EQ("Synced Bookmarks",
867 UTF16ToASCII(browser()->tab_strip_model()->GetActiveWebContents()->
871 int SyncTest::NumberOfDefaultSyncItems() const {
872 return number_of_default_sync_items_
;
875 void SyncTest::SetProxyConfig(net::URLRequestContextGetter
* context_getter
,
876 const net::ProxyConfig
& proxy_config
) {
877 base::WaitableEvent
done(false, false);
878 BrowserThread::PostTask(
879 BrowserThread::IO
, FROM_HERE
,
880 base::Bind(&SetProxyConfigCallback
, &done
,
881 make_scoped_refptr(context_getter
), proxy_config
));
885 void SyncTest::UseFakeServer() {
886 DCHECK_EQ(SERVER_TYPE_UNDECIDED
, server_type_
);
887 server_type_
= IN_PROCESS_FAKE_SERVER
;