This source file includes following definitions.
- OnURLFetchComplete
- running
- IsEncryptionComplete
- IsExitConditionSatisfied
- GetDebugMessage
- SetProxyConfigCallback
- BuildP2PInvalidationService
- BuildSelfNotifyingP2PInvalidationService
- BuildRealisticP2PInvalidationService
- test_server_handle_
- SetUp
- TearDown
- SetUpCommandLine
- AddTestSwitches
- AddOptionalTypesToCommandLine
- MakeProfile
- GetProfile
- GetBrowser
- GetClient
- GetSyncService
- GetSyncServices
- verifier
- DisableVerifier
- SetupClients
- InitializeInstance
- SetupSync
- CleanUpOnMainThread
- SetUpInProcessBrowserTestFixture
- TearDownInProcessBrowserTestFixture
- ReadPasswordFile
- SetupMockGaiaResponses
- SetOAuth2TokenResponse
- ClearMockGaiaResponses
- DecideServerType
- SetUpTestServerIfRequired
- SetUpLocalPythonTestServer
- SetUpLocalTestServer
- TearDownLocalPythonTestServer
- TearDownLocalTestServer
- WaitForTestServerToStart
- IsTestServerRunning
- EnableNetwork
- DisableNetwork
- TestUsesSelfNotifications
- EnableEncryption
- IsEncryptionComplete
- AwaitQuiescence
- ServerSupportsNotificationControl
- DisableNotificationsImpl
- DisableNotifications
- EnableNotificationsImpl
- EnableNotifications
- TriggerNotification
- ServerSupportsErrorTriggering
- TriggerMigrationDoneError
- TriggerBirthdayError
- TriggerTransientError
- TriggerAuthState
- TriggerXmppAuthError
- GetClientToServerResponseErrorType
- GetClientToServerResponseAction
- TriggerSyncError
- TriggerCreateSyncedBookmarks
- SetProxyConfig
#include "chrome/browser/sync/test/integration/sync_test.h"
#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/bookmark_test_helpers.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/invalidation/invalidation_service_factory.h"
#include "chrome/browser/invalidation/p2p_invalidation_service.h"
#include "chrome/browser/invalidation/profile_invalidation_auth_provider.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h"
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/os_crypt/os_crypt.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_browser_thread.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/network_change_notifier.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "sync/engine/sync_scheduler_impl.h"
#include "sync/notifier/p2p_invalidator.h"
#include "sync/protocol/sync.pb.h"
#include "sync/test/fake_server/fake_server.h"
#include "sync/test/fake_server/fake_server_network_resources.h"
#include "url/gurl.h"
using content::BrowserThread;
using invalidation::InvalidationServiceFactory;
namespace switches {
const char kPasswordFileForTest[] = "password-file-for-test";
const char kSyncUserForTest[] = "sync-user-for-test";
const char kSyncPasswordForTest[] = "sync-password-for-test";
const char kSyncServerCommandLine[] = "sync-server-command-line";
}
namespace {
class SyncServerStatusChecker : public net::URLFetcherDelegate {
public:
SyncServerStatusChecker() : running_(false) {}
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
std::string data;
source->GetResponseAsString(&data);
running_ =
(source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
source->GetResponseCode() == 200 && data.find("ok") == 0);
base::MessageLoop::current()->Quit();
}
bool running() const { return running_; }
private:
bool running_;
};
bool IsEncryptionComplete(const ProfileSyncService* service) {
return service->EncryptEverythingEnabled() && !service->encryption_pending();
}
class EncryptionChecker : public SingleClientStatusChangeChecker {
public:
explicit EncryptionChecker(ProfileSyncService* service)
: SingleClientStatusChangeChecker(service) {}
virtual bool IsExitConditionSatisfied() OVERRIDE {
return IsEncryptionComplete(service());
}
virtual std::string GetDebugMessage() const OVERRIDE {
return "Encryption";
}
};
void SetProxyConfigCallback(
base::WaitableEvent* done,
net::URLRequestContextGetter* url_request_context_getter,
const net::ProxyConfig& proxy_config) {
net::ProxyService* proxy_service =
url_request_context_getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(
new net::ProxyConfigServiceFixed(proxy_config));
done->Signal();
}
KeyedService* BuildP2PInvalidationService(
content::BrowserContext* context,
syncer::P2PNotificationTarget notification_target) {
Profile* profile = static_cast<Profile*>(context);
return new invalidation::P2PInvalidationService(
profile,
scoped_ptr<invalidation::InvalidationAuthProvider>(
new invalidation::ProfileInvalidationAuthProvider(
SigninManagerFactory::GetForProfile(profile),
ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
LoginUIServiceFactory::GetForProfile(profile))),
notification_target);
}
KeyedService* BuildSelfNotifyingP2PInvalidationService(
content::BrowserContext* context) {
return BuildP2PInvalidationService(context, syncer::NOTIFY_ALL);
}
KeyedService* BuildRealisticP2PInvalidationService(
content::BrowserContext* context) {
return BuildP2PInvalidationService(context, syncer::NOTIFY_OTHERS);
}
}
SyncTest::SyncTest(TestType test_type)
: test_type_(test_type),
server_type_(SERVER_TYPE_UNDECIDED),
num_clients_(-1),
use_verifier_(true),
notifications_enabled_(true),
test_server_handle_(base::kNullProcessHandle) {
sync_datatype_helper::AssociateWithTest(this);
switch (test_type_) {
case SINGLE_CLIENT:
case SINGLE_CLIENT_LEGACY: {
num_clients_ = 1;
break;
}
case TWO_CLIENT: {
num_clients_ = 2;
break;
}
case MULTIPLE_CLIENT: {
num_clients_ = 3;
break;
}
}
}
SyncTest::~SyncTest() {}
void SyncTest::SetUp() {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (cl->HasSwitch(switches::kPasswordFileForTest)) {
ReadPasswordFile();
} else if (cl->HasSwitch(switches::kSyncUserForTest) &&
cl->HasSwitch(switches::kSyncPasswordForTest)) {
username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest);
password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest);
} else {
username_ = "user@gmail.com";
password_ = "password";
}
if (username_.empty() || password_.empty())
LOG(FATAL) << "Cannot run sync tests without GAIA credentials.";
DecideServerType();
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(true);
#endif
SetUpTestServerIfRequired();
InProcessBrowserTest::SetUp();
}
void SyncTest::TearDown() {
ClearMockGaiaResponses();
InProcessBrowserTest::TearDown();
TearDownLocalPythonTestServer();
TearDownLocalTestServer();
}
void SyncTest::SetUpCommandLine(base::CommandLine* cl) {
AddTestSwitches(cl);
AddOptionalTypesToCommandLine(cl);
}
void SyncTest::AddTestSwitches(base::CommandLine* cl) {
if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
cl->AppendSwitch(switches::kDisableBackgroundNetworking);
if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
}
void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine* cl) {}
Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) {
base::FilePath path;
PathService::Get(chrome::DIR_USER_DATA, &path);
path = path.Append(name);
if (!base::PathExists(path))
CHECK(base::CreateDirectory(path));
Profile* profile =
Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
g_browser_process->profile_manager()->RegisterTestingProfile(profile,
true,
true);
return profile;
}
Profile* SyncTest::GetProfile(int index) {
if (profiles_.empty())
LOG(FATAL) << "SetupClients() has not yet been called.";
if (index < 0 || index >= static_cast<int>(profiles_.size()))
LOG(FATAL) << "GetProfile(): Index is out of bounds.";
return profiles_[index];
}
Browser* SyncTest::GetBrowser(int index) {
if (browsers_.empty())
LOG(FATAL) << "SetupClients() has not yet been called.";
if (index < 0 || index >= static_cast<int>(browsers_.size()))
LOG(FATAL) << "GetBrowser(): Index is out of bounds.";
return browsers_[index];
}
ProfileSyncServiceHarness* SyncTest::GetClient(int index) {
if (clients_.empty())
LOG(FATAL) << "SetupClients() has not yet been called.";
if (index < 0 || index >= static_cast<int>(clients_.size()))
LOG(FATAL) << "GetClient(): Index is out of bounds.";
return clients_[index];
}
ProfileSyncService* SyncTest::GetSyncService(int index) {
return ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
}
std::vector<ProfileSyncService*> SyncTest::GetSyncServices() {
std::vector<ProfileSyncService*> services;
for (int i = 0; i < num_clients(); ++i) {
services.push_back(GetSyncService(i));
}
return services;
}
Profile* SyncTest::verifier() {
if (verifier_ == NULL)
LOG(FATAL) << "SetupClients() has not yet been called.";
return verifier_;
}
void SyncTest::DisableVerifier() {
use_verifier_ = false;
}
bool SyncTest::SetupClients() {
if (num_clients_ <= 0)
LOG(FATAL) << "num_clients_ incorrectly initialized.";
if (!profiles_.empty() || !browsers_.empty() || !clients_.empty())
LOG(FATAL) << "SetupClients() has already been called.";
profiles_.resize(num_clients_);
browsers_.resize(num_clients_);
clients_.resize(num_clients_);
invalidation_forwarders_.resize(num_clients_);
for (int i = 0; i < num_clients_; ++i) {
InitializeInstance(i);
}
verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier"));
test::WaitForBookmarkModelToLoad(
BookmarkModelFactory::GetForProfile(verifier()));
ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
verifier(), Profile::EXPLICIT_ACCESS));
ui_test_utils::WaitForTemplateURLServiceToLoad(
TemplateURLServiceFactory::GetForProfile(verifier()));
return (verifier_ != NULL);
}
void SyncTest::InitializeInstance(int index) {
profiles_[index] = MakeProfile(
base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index));
EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile "
<< index << ".";
browsers_[index] = new Browser(Browser::CreateParams(
GetProfile(index), chrome::GetActiveDesktop()));
EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser "
<< index << ".";
invalidation::P2PInvalidationService* p2p_invalidation_service =
static_cast<invalidation::P2PInvalidationService*>(
InvalidationServiceFactory::GetInstance()->SetTestingFactoryAndUse(
GetProfile(index),
TestUsesSelfNotifications() ?
BuildSelfNotifyingP2PInvalidationService
: BuildRealisticP2PInvalidationService));
p2p_invalidation_service->UpdateCredentials(username_, password_);
ProfileSyncService* profile_sync_service =
ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
if (server_type_ == IN_PROCESS_FAKE_SERVER) {
profile_sync_service->OverrideNetworkResourcesForTest(
make_scoped_ptr<syncer::NetworkResources>(
new fake_server::FakeServerNetworkResources(fake_server_.get())));
}
clients_[index] =
ProfileSyncServiceHarness::Create(
GetProfile(index),
username_,
password_);
EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client "
<< index << ".";
invalidation_forwarders_[index] =
new P2PInvalidationForwarder(clients_[index]->service(),
p2p_invalidation_service);
test::WaitForBookmarkModelToLoad(
BookmarkModelFactory::GetForProfile(GetProfile(index)));
ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
GetProfile(index), Profile::EXPLICIT_ACCESS));
ui_test_utils::WaitForTemplateURLServiceToLoad(
TemplateURLServiceFactory::GetForProfile(GetProfile(index)));
}
bool SyncTest::SetupSync() {
if (profiles_.empty()) {
if (!SetupClients())
LOG(FATAL) << "SetupClients() failed.";
}
for (int i = 0; i < num_clients_; ++i) {
if (!GetClient(i)->SetupSync())
LOG(FATAL) << "SetupSync() failed.";
}
if (TestUsesSelfNotifications()) {
AwaitQuiescence();
}
return true;
}
void SyncTest::CleanUpOnMainThread() {
for (size_t i = 0; i < clients_.size(); ++i) {
clients_[i]->service()->DisableForUser();
}
content::RunAllPendingInMessageLoop();
chrome::CloseAllBrowsers();
content::RunAllPendingInMessageLoop();
CHECK_EQ(0U, chrome::GetTotalBrowserCount());
invalidation_forwarders_.clear();
clients_.clear();
}
void SyncTest::SetUpInProcessBrowserTestFixture() {
net::RuleBasedHostResolverProc* resolver =
new net::RuleBasedHostResolverProc(host_resolver());
resolver->AllowDirectLookup("*.google.com");
resolver->AllowDirectLookup("*.thawte.com");
resolver->AllowDirectLookup("*.geotrust.com");
resolver->AllowDirectLookup("*.gstatic.com");
mock_host_resolver_override_.reset(
new net::ScopedDefaultHostResolverProc(resolver));
}
void SyncTest::TearDownInProcessBrowserTestFixture() {
mock_host_resolver_override_.reset();
}
void SyncTest::ReadPasswordFile() {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest);
if (password_file_.empty())
LOG(FATAL) << "Can't run live server test without specifying --"
<< switches::kPasswordFileForTest << "=<filename>";
std::string file_contents;
base::ReadFileToString(password_file_, &file_contents);
ASSERT_NE(file_contents, "") << "Password file \""
<< password_file_.value() << "\" does not exist.";
std::vector<std::string> tokens;
std::string delimiters = "\r\n";
Tokenize(file_contents, delimiters, &tokens);
ASSERT_EQ(2U, tokens.size()) << "Password file \""
<< password_file_.value()
<< "\" must contain exactly two lines of text.";
username_ = tokens[0];
password_ = tokens[1];
}
void SyncTest::SetupMockGaiaResponses() {
factory_.reset(new net::URLFetcherImplFactory());
fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->get_user_info_url(),
"email=user@gmail.com\ndisplayEmail=user@gmail.com",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->issue_auth_token_url(),
"auth",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GURL(GoogleURLTracker::kSearchDomainCheckURL),
".google.com",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
"some_response",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->oauth2_token_url(),
"{"
" \"refresh_token\": \"rt1\","
" \"access_token\": \"at1\","
" \"expires_in\": 3600,"
" \"token_type\": \"Bearer\""
"}",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->oauth_user_info_url(),
"{"
" \"id\": \"12345\""
"}",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->oauth1_login_url(),
"SID=sid\nLSID=lsid\nAuth=auth_token",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
fake_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->oauth2_revoke_url(),
"",
net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
}
void SyncTest::SetOAuth2TokenResponse(const std::string& response_data,
net::HttpStatusCode response_code,
net::URLRequestStatus::Status status) {
ASSERT_TRUE(NULL != fake_factory_.get());
fake_factory_->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
response_data, response_code, status);
}
void SyncTest::ClearMockGaiaResponses() {
if (fake_factory_) {
fake_factory_->ClearFakeResponses();
fake_factory_.reset();
}
net::URLFetcher::CancelAll();
factory_.reset();
}
void SyncTest::DecideServerType() {
if (server_type_ == SERVER_TYPE_UNDECIDED) {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (!cl->HasSwitch(switches::kSyncServiceURL) &&
!cl->HasSwitch(switches::kSyncServerCommandLine)) {
server_type_ = test_type_ == SINGLE_CLIENT ?
IN_PROCESS_FAKE_SERVER : LOCAL_PYTHON_SERVER;
} else if (cl->HasSwitch(switches::kSyncServiceURL) &&
cl->HasSwitch(switches::kSyncServerCommandLine)) {
server_type_ = LOCAL_LIVE_SERVER;
} else if (cl->HasSwitch(switches::kSyncServiceURL) &&
!cl->HasSwitch(switches::kSyncServerCommandLine)) {
server_type_ = EXTERNAL_LIVE_SERVER;
} else {
LOG(FATAL) << "Can't figure out how to run a server.";
}
}
}
void SyncTest::SetUpTestServerIfRequired() {
if (server_type_ == LOCAL_PYTHON_SERVER) {
if (!SetUpLocalPythonTestServer())
LOG(FATAL) << "Failed to set up local python sync and XMPP servers";
SetupMockGaiaResponses();
} else if (server_type_ == LOCAL_LIVE_SERVER) {
if (username_ == "user@gmail.com" && !SetUpLocalPythonTestServer())
LOG(FATAL) << "Failed to set up local python XMPP server";
if (!SetUpLocalTestServer())
LOG(FATAL) << "Failed to set up local test server";
} else if (server_type_ == IN_PROCESS_FAKE_SERVER) {
fake_server_.reset(new fake_server::FakeServer());
SetUpLocalPythonTestServer();
SetupMockGaiaResponses();
} else if (server_type_ == EXTERNAL_LIVE_SERVER) {
} else {
LOG(FATAL) << "Don't know which server environment to run test in.";
}
}
bool SyncTest::SetUpLocalPythonTestServer() {
EXPECT_TRUE(sync_server_.Start())
<< "Could not launch local python test server.";
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (server_type_ == LOCAL_PYTHON_SERVER) {
std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec();
cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url);
DVLOG(1) << "Started local python sync server at " << sync_service_url;
}
int xmpp_port = 0;
if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) {
LOG(ERROR) << "Could not find valid xmpp_port value";
return false;
}
if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) {
LOG(ERROR) << "Invalid xmpp port: " << xmpp_port;
return false;
}
net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair());
xmpp_host_port_pair.set_port(xmpp_port);
xmpp_port_.reset(new net::ScopedPortException(xmpp_port));
if (!cl->HasSwitch(switches::kSyncNotificationHostPort)) {
cl->AppendSwitchASCII(switches::kSyncNotificationHostPort,
xmpp_host_port_pair.ToString());
cl->AppendSwitch(switches::kSyncAllowInsecureXmppConnection);
}
DVLOG(1) << "Started local python XMPP server at "
<< xmpp_host_port_pair.ToString();
return true;
}
bool SyncTest::SetUpLocalTestServer() {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType server_cmdline_string =
cl->GetSwitchValueNative(switches::kSyncServerCommandLine);
base::CommandLine::StringVector server_cmdline_vector;
base::CommandLine::StringType delimiters(FILE_PATH_LITERAL(" "));
Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector);
base::CommandLine server_cmdline(server_cmdline_vector);
base::LaunchOptions options;
#if defined(OS_WIN)
options.start_hidden = true;
#endif
if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_))
LOG(ERROR) << "Could not launch local test server.";
const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout();
const int kNumIntervals = 15;
if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) {
DVLOG(1) << "Started local test server at "
<< cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
return true;
} else {
LOG(ERROR) << "Could not start local test server at "
<< cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
return false;
}
}
bool SyncTest::TearDownLocalPythonTestServer() {
if (!sync_server_.Stop()) {
LOG(ERROR) << "Could not stop local python test server.";
return false;
}
xmpp_port_.reset();
return true;
}
bool SyncTest::TearDownLocalTestServer() {
if (test_server_handle_ != base::kNullProcessHandle) {
EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false))
<< "Could not stop local test server.";
base::CloseProcessHandle(test_server_handle_);
test_server_handle_ = base::kNullProcessHandle;
}
return true;
}
bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) {
for (int i = 0; i < intervals; ++i) {
if (IsTestServerRunning())
return true;
base::PlatformThread::Sleep(wait / intervals);
}
return false;
}
bool SyncTest::IsTestServerRunning() {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL);
GURL sync_url_status(sync_url.append("/healthz"));
SyncServerStatusChecker delegate;
scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
sync_url_status, net::URLFetcher::GET, &delegate));
fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES);
fetcher->SetRequestContext(g_browser_process->system_request_context());
fetcher->Start();
content::RunMessageLoop();
return delegate.running();
}
void SyncTest::EnableNetwork(Profile* profile) {
SetProxyConfig(profile->GetRequestContext(),
net::ProxyConfig::CreateDirect());
if (notifications_enabled_) {
EnableNotificationsImpl();
}
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
}
void SyncTest::DisableNetwork(Profile* profile) {
DisableNotificationsImpl();
net::ProxyConfig config;
config.proxy_rules().ParseFromString("http=127.0.0.1:0");
SetProxyConfig(profile->GetRequestContext(), config);
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
}
bool SyncTest::TestUsesSelfNotifications() {
return true;
}
bool SyncTest::EnableEncryption(int index) {
ProfileSyncService* service = GetClient(index)->service();
if (::IsEncryptionComplete(service))
return true;
service->EnableEncryptEverything();
const syncer::ModelTypeSet synced_datatypes =
service->GetPreferredDataTypes();
bool sync_everything = synced_datatypes.Equals(syncer::ModelTypeSet::All());
service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
EncryptionChecker checker(service);
checker.Wait();
return !checker.TimedOut();
}
bool SyncTest::IsEncryptionComplete(int index) {
return ::IsEncryptionComplete(GetClient(index)->service());
}
bool SyncTest::AwaitQuiescence() {
return ProfileSyncServiceHarness::AwaitQuiescence(clients());
}
bool SyncTest::ServerSupportsNotificationControl() const {
EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
return server_type_ == LOCAL_PYTHON_SERVER;
}
void SyncTest::DisableNotificationsImpl() {
ASSERT_TRUE(ServerSupportsNotificationControl());
std::string path = "chromiumsync/disablenotifications";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Notifications disabled",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::DisableNotifications() {
DisableNotificationsImpl();
notifications_enabled_ = false;
}
void SyncTest::EnableNotificationsImpl() {
ASSERT_TRUE(ServerSupportsNotificationControl());
std::string path = "chromiumsync/enablenotifications";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Notifications enabled",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::EnableNotifications() {
EnableNotificationsImpl();
notifications_enabled_ = true;
}
void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) {
ASSERT_TRUE(ServerSupportsNotificationControl());
const std::string& data =
syncer::P2PNotificationData(
"from_server",
syncer::NOTIFY_ALL,
syncer::ObjectIdInvalidationMap::InvalidateAll(
syncer::ModelTypeSetToObjectIdSet(changed_types))).ToString();
const std::string& path =
std::string("chromiumsync/sendnotification?channel=") +
syncer::kSyncP2PNotificationChannel + "&data=" + data;
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Notification sent",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
bool SyncTest::ServerSupportsErrorTriggering() const {
EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
return server_type_ == LOCAL_PYTHON_SERVER;
}
void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/migrate";
char joiner = '?';
for (syncer::ModelTypeSet::Iterator it = model_types.First();
it.Good(); it.Inc()) {
path.append(
base::StringPrintf(
"%ctype=%d", joiner,
syncer::GetSpecificsFieldNumberFromModelType(it.Get())));
joiner = '&';
}
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Migration: 200",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::TriggerBirthdayError() {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/birthdayerror";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Birthday error",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::TriggerTransientError() {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/transienterror";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Transient error",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::TriggerAuthState(PythonServerAuthState auth_state) {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/cred";
path.append(auth_state == AUTHENTICATED_TRUE ? "?valid=True" :
"?valid=False");
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
}
void SyncTest::TriggerXmppAuthError() {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/xmppcred";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
}
namespace {
sync_pb::SyncEnums::ErrorType
GetClientToServerResponseErrorType(
syncer::SyncProtocolErrorType error) {
switch (error) {
case syncer::SYNC_SUCCESS:
return sync_pb::SyncEnums::SUCCESS;
case syncer::NOT_MY_BIRTHDAY:
return sync_pb::SyncEnums::NOT_MY_BIRTHDAY;
case syncer::THROTTLED:
return sync_pb::SyncEnums::THROTTLED;
case syncer::CLEAR_PENDING:
return sync_pb::SyncEnums::CLEAR_PENDING;
case syncer::TRANSIENT_ERROR:
return sync_pb::SyncEnums::TRANSIENT_ERROR;
case syncer::MIGRATION_DONE:
return sync_pb::SyncEnums::MIGRATION_DONE;
case syncer::UNKNOWN_ERROR:
return sync_pb::SyncEnums::UNKNOWN;
default:
NOTREACHED();
return sync_pb::SyncEnums::UNKNOWN;
}
}
sync_pb::SyncEnums::Action GetClientToServerResponseAction(
const syncer::ClientAction& action) {
switch (action) {
case syncer::UPGRADE_CLIENT:
return sync_pb::SyncEnums::UPGRADE_CLIENT;
case syncer::CLEAR_USER_DATA_AND_RESYNC:
return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC;
case syncer::ENABLE_SYNC_ON_ACCOUNT:
return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT;
case syncer::STOP_AND_RESTART_SYNC:
return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC;
case syncer::DISABLE_SYNC_ON_CLIENT:
return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT;
case syncer::UNKNOWN_ACTION:
return sync_pb::SyncEnums::UNKNOWN_ACTION;
default:
NOTREACHED();
return sync_pb::SyncEnums::UNKNOWN_ACTION;
}
}
}
void SyncTest::TriggerSyncError(const syncer::SyncProtocolError& error,
SyncErrorFrequency frequency) {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/error";
int error_type =
static_cast<int>(GetClientToServerResponseErrorType(
error.error_type));
int action = static_cast<int>(GetClientToServerResponseAction(
error.action));
path.append(base::StringPrintf("?error=%d", error_type));
path.append(base::StringPrintf("&action=%d", action));
path.append(base::StringPrintf("&error_description=%s",
error.error_description.c_str()));
path.append(base::StringPrintf("&url=%s", error.url.c_str()));
path.append(base::StringPrintf("&frequency=%d", frequency));
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
std::string output = base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
ASSERT_TRUE(output.find("SetError: 200") != base::string16::npos);
}
void SyncTest::TriggerCreateSyncedBookmarks() {
ASSERT_TRUE(ServerSupportsErrorTriggering());
std::string path = "chromiumsync/createsyncedbookmarks";
ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
ASSERT_EQ("Synced Bookmarks",
base::UTF16ToASCII(
browser()->tab_strip_model()->GetActiveWebContents()->
GetTitle()));
}
void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter,
const net::ProxyConfig& proxy_config) {
base::WaitableEvent done(false, false);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyConfigCallback, &done,
make_scoped_refptr(context_getter), proxy_config));
done.Wait();
}