summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrsimha@chromium.org <rsimha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-03 23:27:31 +0000
committerrsimha@chromium.org <rsimha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-03 23:27:31 +0000
commit909a81eaa4568f4b13562dc3f34ac7268b590f09 (patch)
tree958829ea557102634d623123a77f0ae20a7dd6da
parentc09fb1c79c0a3e76dbb6091e4b718fd9bb197395 (diff)
downloadchromium_src-909a81eaa4568f4b13562dc3f34ac7268b590f09.zip
chromium_src-909a81eaa4568f4b13562dc3f34ac7268b590f09.tar.gz
chromium_src-909a81eaa4568f4b13562dc3f34ac7268b590f09.tar.bz2
PyAuto hooks for Sync in TestingAutomationProvider
This patch exposes hooks for sync in TestingAutomationProvider that the chrome pyauto test suite can use. It contains the following changes: - Partial revert of an earlier change to ProfileSyncServiceHarness. Some of its methods were made pure virtual, but this ended up being unnecessary. Also ripped out unnecessary code from LiveSyncTest. - Minor refactor of ProfileSyncServiceHarness to allow for scenarios where the browser is restarted. - A bunch of new methods in TestingAutomationProvider: SignInToSync, GetSyncInfo, AwaitSyncCycleCompletion, EnableSyncForDatatypes and DisableSyncForDatatypes. - A new method in model_type.h/cc called ModelTypeFromString. Required for automation. - New APIs in pyauto.py for sync. - New test suite sync.py with sample tests. BUG=53651, 60970, 56460, 61639 TEST=run pyauto sync tests Review URL: http://codereview.chromium.org/4096004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64988 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc223
-rw-r--r--chrome/browser/automation/testing_automation_provider.h35
-rw-r--r--chrome/browser/profile.cc5
-rw-r--r--chrome/browser/profile.h3
-rw-r--r--chrome/browser/profile_impl.cc4
-rw-r--r--chrome/browser/profile_impl.h1
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.cc86
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.h41
-rw-r--r--chrome/browser/sync/syncable/model_type.cc30
-rw-r--r--chrome/browser/sync/syncable/model_type.h4
-rw-r--r--chrome/test/functional/PYAUTO_TESTS1
-rw-r--r--chrome/test/functional/sync.py52
-rw-r--r--chrome/test/live_sync/live_sync_test.cc27
-rw-r--r--chrome/test/pyautolib/pyauto.py118
-rw-r--r--chrome/test/testing_profile.h3
-rw-r--r--third_party/npapi/bindings/npapi.h4
16 files changed, 570 insertions, 67 deletions
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index c3c8f14..6fc58d3 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -10,6 +10,7 @@
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
#include "base/path_service.h"
+#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
@@ -2113,6 +2114,15 @@ void TestingAutomationProvider::SendJSONRequest(int handle,
handler_map["WaitForNotificationCount"] =
&TestingAutomationProvider::WaitForNotificationCount;
+ handler_map["SignInToSync"] = &TestingAutomationProvider::SignInToSync;
+ handler_map["GetSyncInfo"] = &TestingAutomationProvider::GetSyncInfo;
+ handler_map["AwaitSyncCycleCompletion"] =
+ &TestingAutomationProvider::AwaitSyncCycleCompletion;
+ handler_map["EnableSyncForDatatypes"] =
+ &TestingAutomationProvider::EnableSyncForDatatypes;
+ handler_map["DisableSyncForDatatypes"] =
+ &TestingAutomationProvider::DisableSyncForDatatypes;
+
if (handler_map.find(std::string(command)) != handler_map.end()) {
(this->*handler_map[command])(browser, dict_value, reply_message);
} else {
@@ -3830,6 +3840,219 @@ void TestingAutomationProvider::FillAutoFillProfile(
reply.SendSuccess(NULL);
}
+// Sample json output: { "success": true }
+void TestingAutomationProvider::SignInToSync(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ std::string username;
+ std::string password;
+ if (!args->GetString("username", &username) ||
+ !args->GetString("password", &password)) {
+ reply.SendError("Invalid or missing args");
+ return;
+ }
+ if (sync_waiter_.get() == NULL) {
+ sync_waiter_.reset(new ProfileSyncServiceHarness(
+ browser->profile(), username, password, 0));
+ } else {
+ sync_waiter_->SetCredentials(username, password);
+ }
+ if (sync_waiter_->SetupSync()) {
+ DictionaryValue* return_value = new DictionaryValue;
+ return_value->SetBoolean("success", true);
+ reply.SendSuccess(return_value);
+ } else {
+ reply.SendError("Signing in to sync was unsuccessful");
+ }
+}
+
+// Sample json output:
+// {u'summary': u'SYNC DISABLED'}
+//
+// { u'authenticated': True,
+// u'last synced': u'Just now',
+// u'summary': u'READY',
+// u'sync url': u'clients4.google.com',
+// u'synced datatypes': [ u'Bookmarks',
+// u'Preferences',
+// u'Passwords',
+// u'Autofill',
+// u'Themes',
+// u'Extensions',
+// u'Apps']}
+void TestingAutomationProvider::GetSyncInfo(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ DictionaryValue* sync_info = new DictionaryValue;
+ DictionaryValue* return_value = new DictionaryValue;
+ if (sync_waiter_.get() == NULL) {
+ sync_waiter_.reset(
+ ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
+ }
+ if (!sync_waiter_->IsSyncAlreadySetup()) {
+ sync_info->SetString("summary", "SYNC DISABLED");
+ } else {
+ ProfileSyncService* service = sync_waiter_->service();
+ ProfileSyncService::Status status = sync_waiter_->GetStatus();
+ sync_info->SetString("summary",
+ ProfileSyncService::BuildSyncStatusSummaryText(status.summary));
+ sync_info->SetString("sync url", service->sync_service_url().host());
+ sync_info->SetBoolean("authenticated", status.authenticated);
+ sync_info->SetString("last synced", service->GetLastSyncedTimeString());
+ ListValue* synced_datatype_list = new ListValue;
+ syncable::ModelTypeSet synced_datatypes;
+ service->GetPreferredDataTypes(&synced_datatypes);
+ for (syncable::ModelTypeSet::iterator it = synced_datatypes.begin();
+ it != synced_datatypes.end(); ++it) {
+ synced_datatype_list->Append(
+ new StringValue(syncable::ModelTypeToString(*it)));
+ }
+ sync_info->Set("synced datatypes", synced_datatype_list);
+ }
+ return_value->Set("sync_info", sync_info);
+ reply.SendSuccess(return_value);
+}
+
+// Sample json output: { "success": true }
+void TestingAutomationProvider::AwaitSyncCycleCompletion(
+ Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ if (sync_waiter_.get() == NULL) {
+ sync_waiter_.reset(
+ ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
+ }
+ if (!sync_waiter_->IsSyncAlreadySetup()) {
+ reply.SendError("Not signed in to sync");
+ return;
+ }
+ sync_waiter_->AwaitSyncCycleCompletion("Waiting for sync cycle");
+ ProfileSyncService::Status status = sync_waiter_->GetStatus();
+ if (status.summary == ProfileSyncService::Status::READY) {
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetBoolean("success", true);
+ reply.SendSuccess(return_value.get());
+ } else {
+ reply.SendError("Wait for sync cycle was unsuccessful");
+ }
+}
+
+// Refer to EnableSyncForDatatypes() in chrome/test/pyautolib/pyauto.py for
+// sample json input. Sample json output: { "success": true }
+void TestingAutomationProvider::EnableSyncForDatatypes(
+ Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ if (sync_waiter_.get() == NULL) {
+ sync_waiter_.reset(
+ ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
+ }
+ if (!sync_waiter_->IsSyncAlreadySetup()) {
+ reply.SendError("Not signed in to sync");
+ return;
+ }
+ ListValue* datatypes = NULL;
+ if (!args->GetList("datatypes", &datatypes)) {
+ reply.SendError("Invalid or missing args");
+ return;
+ }
+ std::string first_datatype;
+ datatypes->GetString(0, &first_datatype);
+ if (first_datatype == "All") {
+ sync_waiter_->EnableSyncForAllDatatypes();
+ } else {
+ int num_datatypes = datatypes->GetSize();
+ for (int i = 0; i < num_datatypes; ++i) {
+ std::string datatype_string;
+ datatypes->GetString(i, &datatype_string);
+ syncable::ModelType datatype =
+ syncable::ModelTypeFromString(datatype_string);
+ if (datatype == syncable::UNSPECIFIED) {
+ AutomationJSONReply(this, reply_message).SendError(StringPrintf(
+ "Invalid datatype string: %s.", datatype_string.c_str()));
+ return;
+ }
+ sync_waiter_->EnableSyncForDatatype(datatype);
+ sync_waiter_->AwaitSyncCycleCompletion(StringPrintf(
+ "Enabling datatype: %s", datatype_string.c_str()));
+ }
+ }
+ ProfileSyncService::Status status = sync_waiter_->GetStatus();
+ if (status.summary == ProfileSyncService::Status::READY ||
+ status.summary == ProfileSyncService::Status::SYNCING) {
+ DictionaryValue* return_value = new DictionaryValue;
+ return_value->SetBoolean("success", true);
+ reply.SendSuccess(return_value);
+ } else {
+ reply.SendError("Enabling sync for given datatypes was unsuccessful");
+ }
+}
+
+// Refer to DisableSyncForDatatypes() in chrome/test/pyautolib/pyauto.py for
+// sample json input. Sample json output: { "success": true }
+void TestingAutomationProvider::DisableSyncForDatatypes(
+ Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ if (sync_waiter_.get() == NULL) {
+ sync_waiter_.reset(
+ ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
+ }
+ if (!sync_waiter_->IsSyncAlreadySetup()) {
+ reply.SendError("Not signed in to sync");
+ return;
+ }
+ ListValue* datatypes = NULL;
+ if (!args->GetList("datatypes", &datatypes)) {
+ reply.SendError("Invalid or missing args");
+ return;
+ }
+ std::string first_datatype;
+ datatypes->GetString(0, &first_datatype);
+ if (first_datatype == "All") {
+ sync_waiter_->DisableSyncForAllDatatypes();
+ ProfileSyncService::Status status = sync_waiter_->GetStatus();
+ if (status.summary != ProfileSyncService::Status::READY &&
+ status.summary != ProfileSyncService::Status::SYNCING) {
+ DictionaryValue* return_value = new DictionaryValue;
+ return_value->SetBoolean("success", true);
+ reply.SendSuccess(return_value);
+ } else {
+ reply.SendError("Disabling all sync datatypes was unsuccessful");
+ }
+ } else {
+ int num_datatypes = datatypes->GetSize();
+ for (int i = 0; i < num_datatypes; i++) {
+ std::string datatype_string;
+ datatypes->GetString(i, &datatype_string);
+ syncable::ModelType datatype =
+ syncable::ModelTypeFromString(datatype_string);
+ if (datatype == syncable::UNSPECIFIED) {
+ AutomationJSONReply(this, reply_message).SendError(StringPrintf(
+ "Invalid datatype string: %s.", datatype_string.c_str()));
+ return;
+ }
+ sync_waiter_->DisableSyncForDatatype(datatype);
+ sync_waiter_->AwaitSyncCycleCompletion(StringPrintf(
+ "Disabling datatype: %s", datatype_string.c_str()));
+ }
+ ProfileSyncService::Status status = sync_waiter_->GetStatus();
+ if (status.summary == ProfileSyncService::Status::READY ||
+ status.summary == ProfileSyncService::Status::SYNCING) {
+ DictionaryValue* return_value = new DictionaryValue;
+ return_value->SetBoolean("success", true);
+ reply.SendSuccess(return_value);
+ } else {
+ reply.SendError("Disabling sync for given datatypes was unsuccessful");
+ }
+ }
+}
+
/* static */
ListValue* TestingAutomationProvider::GetListFromAutoFillProfiles(
const std::vector<AutoFillProfile*>& autofill_profiles) {
diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h
index dc76603..8cd999d 100644
--- a/chrome/browser/automation/testing_automation_provider.h
+++ b/chrome/browser/automation/testing_automation_provider.h
@@ -7,9 +7,11 @@
#pragma once
#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/automation/automation_provider.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/history/history.h"
+#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/common/notification_registrar.h"
class DictionaryValue;
@@ -612,6 +614,36 @@ class TestingAutomationProvider : public AutomationProvider,
DictionaryValue* args,
IPC::Message* reply_message);
+ // Signs in to sync using the given username and password.
+ // Uses the JSON interface for input/output.
+ void SignInToSync(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+ // Returns info about sync.
+ // Uses the JSON interface for input/output.
+ void GetSyncInfo(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+ // Waits for the ongoing sync cycle to complete.
+ // Uses the JSON interface for input/output.
+ void AwaitSyncCycleCompletion(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+ // Enables sync for one or more sync datatypes.
+ // Uses the JSON interface for input/output.
+ void EnableSyncForDatatypes(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+ // Disables sync for one or more sync datatypes.
+ // Uses the JSON interface for input/output.
+ void DisableSyncForDatatypes(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
// Translate DictionaryValues of autofill profiles and credit cards to the
// data structure used in the browser.
// Args:
@@ -702,6 +734,9 @@ class TestingAutomationProvider : public AutomationProvider,
PopupMenuWaiter* popup_menu_waiter_;
#endif // defined(TOOLKIT_VIEWS)
+ // Used to wait on various browser sync events.
+ scoped_ptr<ProfileSyncServiceHarness> sync_waiter_;
+
// Handle for an in-process redirect query. We expect only one redirect query
// at a time (we should have only one caller, and it will block while waiting
// for the results) so there is only one handle. When non-0, indicates a
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index bd0c5c8..bc5ba44 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -424,6 +424,11 @@ class OffTheRecordProfileImpl : public Profile,
return false;
}
+ virtual bool HasProfileSyncService() const {
+ // We never have a profile sync service.
+ return false;
+ }
+
virtual bool DidLastSessionExitCleanly() {
return profile_->DidLastSessionExitCleanly();
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index fac699d..aac3f02 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -379,6 +379,9 @@ class Profile {
// Returns true if this profile has a session service.
virtual bool HasSessionService() const = 0;
+ // Returns true if this profile has a profile sync service.
+ virtual bool HasProfileSyncService() const = 0;
+
// Returns true if the last time this profile was open it was exited cleanly.
virtual bool DidLastSessionExitCleanly() = 0;
diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc
index 8b046ed..20e513f 100644
--- a/chrome/browser/profile_impl.cc
+++ b/chrome/browser/profile_impl.cc
@@ -1089,6 +1089,10 @@ bool ProfileImpl::HasSessionService() const {
return (session_service_.get() != NULL);
}
+bool ProfileImpl::HasProfileSyncService() const {
+ return (sync_service_.get() != NULL);
+}
+
bool ProfileImpl::DidLastSessionExitCleanly() {
// last_session_exited_cleanly_ is set when the preferences are loaded. Force
// it to be set by asking for the prefs.
diff --git a/chrome/browser/profile_impl.h b/chrome/browser/profile_impl.h
index 6bad987..9834fc1 100644
--- a/chrome/browser/profile_impl.h
+++ b/chrome/browser/profile_impl.h
@@ -94,6 +94,7 @@ class ProfileImpl : public Profile,
virtual SessionService* GetSessionService();
virtual void ShutdownSessionService();
virtual bool HasSessionService() const;
+ virtual bool HasProfileSyncService() const;
virtual bool DidLastSessionExitCleanly();
virtual BookmarkModel* GetBookmarkModel();
virtual bool IsSameProfile(Profile* profile);
diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc
index 3ecafb7..4750033 100644
--- a/chrome/browser/sync/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/profile_sync_service_harness.cc
@@ -84,18 +84,44 @@ bool StateChangeTimeoutEvent::Abort() {
}
ProfileSyncServiceHarness::ProfileSyncServiceHarness(
- Profile* p,
+ Profile* profile,
const std::string& username,
const std::string& password,
int id)
- : wait_state_(WAITING_FOR_ON_BACKEND_INITIALIZED),
- profile_(p),
+ : wait_state_(INITIAL_WAIT_STATE),
+ profile_(profile),
service_(NULL),
last_timestamp_(0),
min_timestamp_needed_(kMinTimestampNeededNone),
username_(username),
password_(password),
- id_(id) {}
+ id_(id) {
+ if (IsSyncAlreadySetup()) {
+ service_ = profile_->GetProfileSyncService();
+ service_->AddObserver(this);
+ wait_state_ = FULLY_SYNCED;
+ }
+}
+
+// static
+ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateAndAttach(
+ Profile* profile) {
+ if (!profile->HasProfileSyncService()) {
+ NOTREACHED() << "Profile has never signed into sync.";
+ return NULL;
+ }
+ return new ProfileSyncServiceHarness(profile, "", "", 0);
+}
+
+void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
+ const std::string& password) {
+ username_ = username;
+ password_ = password;
+}
+
+bool ProfileSyncServiceHarness::IsSyncAlreadySetup() {
+ return profile_->HasProfileSyncService();
+}
bool ProfileSyncServiceHarness::SetupSync() {
syncable::ModelTypeSet synced_datatypes;
@@ -109,7 +135,7 @@ bool ProfileSyncServiceHarness::SetupSync() {
bool ProfileSyncServiceHarness::SetupSync(
const syncable::ModelTypeSet& synced_datatypes) {
// Initialize the sync client's profile sync service object.
- service_ = profile_->GetProfileSyncService("");
+ service_ = profile_->GetProfileSyncService();
if (service_ == NULL) {
LOG(ERROR) << "SetupSync(): service_ is null.";
return false;
@@ -123,7 +149,7 @@ bool ProfileSyncServiceHarness::SetupSync(
service_->signin()->StartSignIn(username_, password_, "", "");
// Wait for the OnBackendInitialized() callback.
- DCHECK_EQ(wait_state_, WAITING_FOR_ON_BACKEND_INITIALIZED);
+ wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
"Waiting for OnBackendInitialized().")) {
LOG(ERROR) << "OnBackendInitialized() not seen after "
@@ -148,6 +174,9 @@ bool ProfileSyncServiceHarness::SetupSync(
return false;
}
+ // Indicate to the browser that sync setup is complete.
+ service()->SetSyncSetupCompleted();
+
return true;
}
@@ -157,6 +186,10 @@ void ProfileSyncServiceHarness::SignalStateCompleteWithNextState(
SignalStateComplete();
}
+void ProfileSyncServiceHarness::SignalStateComplete() {
+ MessageLoop::current()->Quit();
+}
+
bool ProfileSyncServiceHarness::RunStateChangeMachine() {
WaitState original_wait_state = wait_state_;
switch (wait_state_) {
@@ -353,13 +386,16 @@ bool ProfileSyncServiceHarness::AwaitStatusChangeWithTimeout(
}
scoped_refptr<StateChangeTimeoutEvent> timeout_signal(
new StateChangeTimeoutEvent(this, reason));
- MessageLoopForUI* loop = MessageLoopForUI::current();
+ MessageLoop* loop = MessageLoop::current();
+ bool did_allow_nestable_tasks = loop->NestableTasksAllowed();
+ loop->SetNestableTasksAllowed(true);
loop->PostDelayedTask(
FROM_HERE,
NewRunnableMethod(timeout_signal.get(),
&StateChangeTimeoutEvent::Callback),
timeout_milliseconds);
- AwaitStatusChange();
+ loop->Run();
+ loop->SetNestableTasksAllowed(did_allow_nestable_tasks);
LogClientInfo("AwaitStatusChangeWithTimeout succeeded");
return timeout_signal->Abort();
}
@@ -370,11 +406,12 @@ ProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() {
}
bool ProfileSyncServiceHarness::IsSynced() {
+ if (service() == NULL)
+ return false;
const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
// TODO(rsimha): Remove additional checks of snap->has_more_to_sync and
// snap->unsynced_count once http://crbug.com/48989 is fixed.
- return (service() &&
- snap &&
+ return (snap &&
ServiceIsPushingChanges() &&
GetStatus().notifications_enabled &&
!service()->backend()->HasUnsyncedItems() &&
@@ -478,19 +515,24 @@ int64 ProfileSyncServiceHarness::GetUpdatedTimestamp() {
}
void ProfileSyncServiceHarness::LogClientInfo(std::string message) {
- const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
- if (snap) {
- VLOG(1) << "Client " << id_ << ": " << message
- << ": max_local_timestamp: " << snap->max_local_timestamp
- << ", has_more_to_sync: " << snap->has_more_to_sync
- << ", unsynced_count: " << snap->unsynced_count
- << ", has_unsynced_items: "
- << service()->backend()->HasUnsyncedItems()
- << ", notifications_enabled: "
- << GetStatus().notifications_enabled
- << ", service_is_pushing_changes: " << ServiceIsPushingChanges();
+ if (service()) {
+ const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
+ if (snap) {
+ VLOG(1) << "Client " << id_ << ": " << message
+ << ": max_local_timestamp: " << snap->max_local_timestamp
+ << ", has_more_to_sync: " << snap->has_more_to_sync
+ << ", unsynced_count: " << snap->unsynced_count
+ << ", has_unsynced_items: "
+ << service()->backend()->HasUnsyncedItems()
+ << ", notifications_enabled: "
+ << GetStatus().notifications_enabled
+ << ", service_is_pushing_changes: " << ServiceIsPushingChanges();
+ } else {
+ VLOG(1) << "Client " << id_ << ": " << message
+ << ": Sync session snapshot not available.";
+ }
} else {
VLOG(1) << "Client " << id_ << ": " << message
- << ": Sync session snapshot not available.";
+ << ": Sync service not available.";
}
}
diff --git a/chrome/browser/sync/profile_sync_service_harness.h b/chrome/browser/sync/profile_sync_service_harness.h
index 90f4540..a50bb8a 100644
--- a/chrome/browser/sync/profile_sync_service_harness.h
+++ b/chrome/browser/sync/profile_sync_service_harness.h
@@ -20,18 +20,27 @@ class Profile;
// automation purposes. It harnesses the ProfileSyncService member of the
// profile passed to it on construction and automates certain things like setup
// and authentication. It provides ways to "wait" adequate periods of time for
-// several clients to get to the same state. In order to use this class for
-// automation, derived classes must implement 2 methods: SignalStateComplete()
-// and AwaitStatusChange().
+// several clients to get to the same state.
class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
public:
- ProfileSyncServiceHarness(Profile* p,
+ ProfileSyncServiceHarness(Profile* profile,
const std::string& username,
const std::string& password,
int id);
virtual ~ProfileSyncServiceHarness() {}
+ // Creates a ProfileSyncServiceHarness object and attaches it to |profile|, a
+ // profile that is assumed to have been signed into sync in the past. Caller
+ // takes ownership.
+ static ProfileSyncServiceHarness* CreateAndAttach(Profile* profile);
+
+ // Sets the GAIA credentials with which to sign in to sync.
+ void SetCredentials(const std::string& username, const std::string& password);
+
+ // Returns true if sync has been enabled on |profile_|.
+ bool IsSyncAlreadySetup();
+
// Creates a ProfileSyncService for the profile passed at construction and
// enables sync for all available datatypes. Returns true only after sync has
// been fully initialized and authenticated, and we are ready to process
@@ -109,8 +118,11 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
friend class StateChangeTimeoutEvent;
enum WaitState {
+ // The sync client has just been initialized.
+ INITIAL_WAIT_STATE = 0,
+
// The sync client awaits the OnBackendInitialized() callback.
- WAITING_FOR_ON_BACKEND_INITIALIZED = 0,
+ WAITING_FOR_ON_BACKEND_INITIALIZED,
// The sync client is waiting for the first sync cycle to complete.
WAITING_FOR_INITIAL_SYNC,
@@ -139,10 +151,8 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
// Called from the observer when the current wait state has been completed.
void SignalStateCompleteWithNextState(WaitState next_state);
- // Indicates that the operation being waited on is complete. Derived classes
- // may implement this either by quitting the UI message loop, or by signaling
- // a WaitableEvent object.
- virtual void SignalStateComplete() = 0;
+ // Indicates that the operation being waited on is complete.
+ void SignalStateComplete();
// Finite state machine for controlling state. Returns true only if a state
// change has taken place.
@@ -152,26 +162,21 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
bool AwaitStatusChangeWithTimeout(int timeout_milliseconds,
const std::string& reason);
- // Waits until the sync client's status changes. Derived classes may implement
- // this either by running the UI message loop, or by waiting on a
- // WaitableEvent object.
- virtual void AwaitStatusChange() = 0;
-
// Returns true if the sync client has no unsynced items.
bool IsSynced();
// Logs message with relevant info about client's sync state (if available).
void LogClientInfo(std::string message);
+ // Updates |last_timestamp_| with the timestamp of the current sync session.
+ // Returns the new value of |last_timestamp_|.
+ int64 GetUpdatedTimestamp();
+
WaitState wait_state_;
Profile* profile_;
ProfileSyncService* service_;
- // Updates |last_timestamp_| with the timestamp of the current sync session.
- // Returns the new value of |last_timestamp_|.
- int64 GetUpdatedTimestamp();
-
// This value tracks the max sync timestamp (e.g. synced-to revision) inside
// the sync engine. It gets updated when a sync cycle ends and the session
// snapshot implies syncing is "done".
diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc
index 5a06be8..2d17ebc 100644
--- a/chrome/browser/sync/syncable/model_type.cc
+++ b/chrome/browser/sync/syncable/model_type.cc
@@ -150,6 +150,33 @@ std::string ModelTypeToString(ModelType model_type) {
}
}
+ModelType ModelTypeFromString(const std::string& model_type_string) {
+ if (model_type_string == "Bookmarks")
+ return BOOKMARKS;
+ else if (model_type_string == "Preferences")
+ return PREFERENCES;
+ else if (model_type_string == "Passwords")
+ return PASSWORDS;
+ else if (model_type_string == "Autofill")
+ return AUTOFILL;
+ else if (model_type_string == "Themes")
+ return THEMES;
+ else if (model_type_string == "Typed URLs")
+ return TYPED_URLS;
+ else if (model_type_string == "Extensions")
+ return EXTENSIONS;
+ else if (model_type_string == "Encryption keys")
+ return NIGORI;
+ else if (model_type_string == "Sessions")
+ return SESSIONS;
+ else if (model_type_string == "Apps")
+ return APPS;
+ else
+ NOTREACHED() << "No known model type corresponding to "
+ << model_type_string << ".";
+ return UNSPECIFIED;
+}
+
// TODO(akalin): Figure out a better way to do these mappings.
namespace {
@@ -247,8 +274,7 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kSessionNotificationType) {
*model_type = SESSIONS;
return true;
- }
- else if (notification_type == kUnknownNotificationType) {
+ } else if (notification_type == kUnknownNotificationType) {
// TODO(akalin): This is a hack to make new sync data types work with
// server-issued notifications. Remove this when it's not needed
// anymore.
diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h
index 077d243..c619b7e 100644
--- a/chrome/browser/sync/syncable/model_type.h
+++ b/chrome/browser/sync/syncable/model_type.h
@@ -89,8 +89,12 @@ ModelType GetModelType(const sync_pb::SyncEntity& sync_entity);
// prefer using GetModelType where possible.
ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics);
+// Returns a string that represents the name of |model_type|.
std::string ModelTypeToString(ModelType model_type);
+// Returns the ModelType corresponding to the name |model_type_string|.
+ModelType ModelTypeFromString(const std::string& model_type_string);
+
// Convert a real model type to a notification type (used for
// subscribing to server-issued notifications). Returns true iff
// |model_type| was a real model type and |notification_type| was
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index 87f8641..dad55c1 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -47,6 +47,7 @@
'prefs',
'search_engines',
'special_tabs',
+ # 'sync', crbug.com/60970
'test_basic.SimpleTest.testCanOpenGoogle',
'themes',
'translate',
diff --git a/chrome/test/functional/sync.py b/chrome/test/functional/sync.py
new file mode 100644
index 0000000..fc9dd074
--- /dev/null
+++ b/chrome/test/functional/sync.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import pyauto_functional # Must be imported before pyauto
+import pyauto
+
+
+class SyncTest(pyauto.PyUITest):
+ """Tests for sync."""
+
+ def testSignInToSync(self):
+ """Sign in to sync."""
+ # Need to initialize username and password. See crbug.com/60970.
+ username = '<username>@gmail.com'
+ password = '<password>'
+ self.assertTrue(self.GetSyncInfo()['summary'] == 'OFFLINE_UNUSABLE')
+ self.assertTrue(self.GetSyncInfo()['last synced'] == 'Never')
+ self.assertTrue(self.SignInToSync(username, password))
+ self.assertTrue(self.GetSyncInfo()['summary'] == 'READY')
+ self.assertTrue(self.GetSyncInfo()['last synced'] == 'Just now')
+
+ def testDisableAndEnableDatatype(self):
+ """Sign in, disable and then enable sync for a datatype."""
+ # Need to initialize username and password. See crbug.com/60970.
+ username = '<username>@gmail.com'
+ password = '<password>'
+ self.assertTrue(self.SignInToSync(username, password))
+ self.assertTrue(self.GetSyncInfo()['summary'] == 'READY')
+ self.assertTrue(self.GetSyncInfo()['last synced'] == 'Just now')
+ self.assertTrue(self.DisableSyncForDatatypes(['Bookmarks']))
+ self.assertFalse('Bookmarks' in self.GetSyncInfo()['synced datatypes'])
+ self.assertTrue(self.EnableSyncForDatatypes(['Bookmarks']))
+ self.assertTrue('Bookmarks' in self.GetSyncInfo()['synced datatypes'])
+
+ def testRestartBrowser(self):
+ """Sign in to sync and restart the browser."""
+ # Need to initialize username and password. See crbug.com/60970.
+ username = '<username>@gmail.com'
+ password = '<password>'
+ self.assertTrue(self.SignInToSync(username, password))
+ self.assertTrue(self.GetSyncInfo()['summary'] == 'READY')
+ self.assertTrue(self.GetSyncInfo()['last synced'] == 'Just now')
+ self.RestartBrowser(clear_profile=False)
+ self.assertTrue(self.AwaitSyncCycleCompletion())
+ self.assertTrue(self.GetSyncInfo()['summary'] == 'READY')
+ self.assertTrue(self.GetSyncInfo()['last synced'] == 'Just now')
+
+
+if __name__ == '__main__':
+ pyauto_functional.Main()
diff --git a/chrome/test/live_sync/live_sync_test.cc b/chrome/test/live_sync/live_sync_test.cc
index 8b614be..062df35 100644
--- a/chrome/test/live_sync/live_sync_test.cc
+++ b/chrome/test/live_sync/live_sync_test.cc
@@ -86,30 +86,6 @@ class SetProxyConfigTask : public Task {
net::ProxyConfig proxy_config_;
};
-// This is a our notion of a sync client for automation purposes. It is a helper
-// class that specializes ProfileSyncServiceHarness, and is used to wait on
-// various sync operations.
-class SyncClient : public ProfileSyncServiceHarness {
- public:
- SyncClient(Profile* profile,
- const std::string& username,
- const std::string& password, int id)
- : ProfileSyncServiceHarness(profile, username, password, id) {}
-
- virtual ~SyncClient() {}
-
- // Indicates that the sync operation being waited on is complete. Overrides
- // ProfileSyncServiceHarness::SignalStateComplete().
- virtual void SignalStateComplete() { MessageLoopForUI::current()->Quit(); }
-
- // Waits until the sync client's status changes. Overrides
- // ProfileSyncServiceHarness::AwaitStatusChange().
- virtual void AwaitStatusChange() { ui_test_utils::RunMessageLoop(); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SyncClient);
-};
-
void LiveSyncTest::SetUp() {
// At this point, the browser hasn't been launched, and no services are
// available. But we can verify our command line parameters and fail
@@ -205,7 +181,8 @@ bool LiveSyncTest::SetupClients() {
profiles_.push_back(MakeProfile(
StringPrintf(FILE_PATH_LITERAL("Profile%d"), i)));
EXPECT_FALSE(GetProfile(i) == NULL) << "GetProfile(" << i << ") failed.";
- clients_.push_back(new SyncClient(GetProfile(i), username_, password_, i));
+ clients_.push_back(
+ new ProfileSyncServiceHarness(GetProfile(i), username_, password_, i));
EXPECT_FALSE(GetClient(i) == NULL) << "GetClient(" << i << ") failed.";
}
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index a152c7e..815415a 100644
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -1630,6 +1630,124 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
logging.debug('Executing javascript: ', js)
return self.ExecuteJavascript(js, windex, tab_index)
+ def SignInToSync(self, username, password):
+ """Signs in to sync using the given username and password.
+
+ Args:
+ username: The account with which to sign in. Example: "user@gmail.com".
+ password: Password for the above account. Example: "pa$$w0rd".
+
+ Returns:
+ True, on success.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'SignInToSync',
+ 'username': username,
+ 'password': password,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['success']
+
+ def GetSyncInfo(self):
+ """Returns info about sync.
+
+ Returns:
+ A dictionary of info about sync.
+ Example dictionaries:
+ {u'summary': u'SYNC DISABLED'}
+
+ { u'authenticated': True,
+ u'last synced': u'Just now',
+ u'summary': u'READY',
+ u'sync url': u'clients4.google.com',
+ u'synced datatypes': [ u'Bookmarks',
+ u'Preferences',
+ u'Passwords',
+ u'Autofill',
+ u'Themes',
+ u'Extensions',
+ u'Apps']}
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'GetSyncInfo',
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['sync_info']
+
+ def AwaitSyncCycleCompletion(self):
+ """Waits for the ongoing sync cycle to complete. Must be signed in to sync
+ before calling this method.
+
+ Returns:
+ True, on success.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'AwaitSyncCycleCompletion',
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['success']
+
+ def EnableSyncForDatatypes(self, datatypes):
+ """Enables sync for a given list of sync datatypes. Must be signed in to
+ sync before calling this method.
+
+ Args:
+ datatypes: A list of strings indicating the datatypes for which to enable
+ sync. Strings that can be in the list are:
+ Bookmarks, Preferences, Passwords, Autofill, Themes,
+ Typed URLs, Extensions, Encryption keys, Sessions, Apps, All.
+ For an updated list of valid sync datatypes, refer to the
+ function ModelTypeToString() in the file
+ chrome/browser/sync/syncable/model_type.cc.
+ Examples:
+ ['Bookmarks', 'Preferences', 'Passwords']
+ ['All']
+
+ Returns:
+ True, on success.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'EnableSyncForDatatypes',
+ 'datatypes': datatypes,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['success']
+
+ def DisableSyncForDatatypes(self, datatypes):
+ """Disables sync for a given list of sync datatypes. Must be signed in to
+ sync before calling this method.
+
+ Args:
+ datatypes: A list of strings indicating the datatypes for which to
+ disable sync. Strings that can be in the list are:
+ Bookmarks, Preferences, Passwords, Autofill, Themes,
+ Typed URLs, Extensions, Encryption keys, Sessions, Apps, All.
+ For an updated list of valid sync datatypes, refer to the
+ function ModelTypeToString() in the file
+ chrome/browser/sync/syncable/model_type.cc.
+ Examples:
+ ['Bookmarks', 'Preferences', 'Passwords']
+ ['All']
+
+ Returns:
+ True, on success.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'DisableSyncForDatatypes',
+ 'datatypes': datatypes,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict)['success']
class PyUITestSuite(pyautolib.PyUITestSuiteBase, unittest.TestSuite):
"""Base TestSuite for PyAuto UI tests."""
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 7cbe718..5604b15 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -240,6 +240,9 @@ class TestingProfile : public Profile {
virtual bool HasSessionService() const {
return (session_service_.get() != NULL);
}
+ virtual bool HasProfileSyncService() const {
+ return (profile_sync_service_.get() != NULL);
+ }
virtual std::wstring GetName() { return std::wstring(); }
virtual void SetName(const std::wstring& name) {}
virtual std::wstring GetID() { return id_; }
diff --git a/third_party/npapi/bindings/npapi.h b/third_party/npapi/bindings/npapi.h
index e4693f2..3d31eab 100644
--- a/third_party/npapi/bindings/npapi.h
+++ b/third_party/npapi/bindings/npapi.h
@@ -73,9 +73,13 @@
/* BEGIN GOOGLE MODIFICATIONS */
/* On Linux and Mac, be sure to set Mozilla-specific macros. */
#if defined(USE_X11)
+#if !defined(XP_UNIX)
#define XP_UNIX 1
+#endif
+#if !defined(MOZ_X11)
#define MOZ_X11 1
#endif
+#endif
/* END GOOGLE MODIFICATIONS */
#if defined(__SYMBIAN32__)