diff options
-rw-r--r-- | chrome/browser/automation/testing_automation_provider.cc | 223 | ||||
-rw-r--r-- | chrome/browser/automation/testing_automation_provider.h | 35 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 5 | ||||
-rw-r--r-- | chrome/browser/profile.h | 3 | ||||
-rw-r--r-- | chrome/browser/profile_impl.cc | 4 | ||||
-rw-r--r-- | chrome/browser/profile_impl.h | 1 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_harness.cc | 86 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_harness.h | 41 | ||||
-rw-r--r-- | chrome/browser/sync/syncable/model_type.cc | 30 | ||||
-rw-r--r-- | chrome/browser/sync/syncable/model_type.h | 4 | ||||
-rw-r--r-- | chrome/test/functional/PYAUTO_TESTS | 1 | ||||
-rw-r--r-- | chrome/test/functional/sync.py | 52 | ||||
-rw-r--r-- | chrome/test/live_sync/live_sync_test.cc | 27 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyauto.py | 118 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 3 | ||||
-rw-r--r-- | third_party/npapi/bindings/npapi.h | 4 |
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__) |