diff options
author | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-18 20:19:05 +0000 |
---|---|---|
committer | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-18 20:19:05 +0000 |
commit | e264060920c1a56685eaccbb0ace72f1050e9b2c (patch) | |
tree | d70fb9e6018ddddc5acf9e760ddfb35e3bf0d20c /chrome/browser/password_manager | |
parent | 6dfd1d71ad9c6b7b0f8c822a2d8ba84be85038bf (diff) | |
download | chromium_src-e264060920c1a56685eaccbb0ace72f1050e9b2c.zip chromium_src-e264060920c1a56685eaccbb0ace72f1050e9b2c.tar.gz chromium_src-e264060920c1a56685eaccbb0ace72f1050e9b2c.tar.bz2 |
Componentize PasswordSyncableService
This just moves the files and adds needed dependencies.
BUG=344456
TBR=atwilson@chromium.org,rvargas@chromium.org
Review URL: https://codereview.chromium.org/170313003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251818 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/password_manager')
3 files changed, 0 insertions, 1177 deletions
diff --git a/chrome/browser/password_manager/password_syncable_service.cc b/chrome/browser/password_manager/password_syncable_service.cc deleted file mode 100644 index 4bee8dc..0000000 --- a/chrome/browser/password_manager/password_syncable_service.cc +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2013 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. - -#include "chrome/browser/password_manager/password_syncable_service.h" - -#include "base/location.h" -#include "base/memory/scoped_vector.h" -#include "base/metrics/histogram.h" -#include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/common/password_form.h" -#include "components/password_manager/core/browser/password_store.h" -#include "net/base/escape.h" -#include "sync/api/sync_error_factory.h" - -namespace { - -// Describes the result of merging sync and local passwords. -enum MergeResult { - IDENTICAL, - SYNC, - LOCAL, -}; - -// Merges the local and sync passwords and outputs the entry into -// |new_password_form|. Returns MergeResult value describing the content of -// |new_password_form|. -MergeResult MergeLocalAndSyncPasswords( - const sync_pb::PasswordSpecificsData& password_specifics, - const autofill::PasswordForm& password_form, - autofill::PasswordForm* new_password_form) { - DCHECK(new_password_form); - if (password_form.scheme == password_specifics.scheme() && - password_form.signon_realm == password_specifics.signon_realm() && - password_form.origin.spec() == password_specifics.origin() && - password_form.action.spec() == password_specifics.action() && - base::UTF16ToUTF8(password_form.username_element) == - password_specifics.username_element() && - base::UTF16ToUTF8(password_form.password_element) == - password_specifics.password_element() && - base::UTF16ToUTF8(password_form.username_value) == - password_specifics.username_value() && - base::UTF16ToUTF8(password_form.password_value) == - password_specifics.password_value() && - password_form.ssl_valid == password_specifics.ssl_valid() && - password_form.preferred == password_specifics.preferred() && - password_form.date_created.ToInternalValue() == - password_specifics.date_created() && - password_form.blacklisted_by_user == password_specifics.blacklisted()) { - return IDENTICAL; - } - - // If the passwords differ, take the one that was created more recently. - if (base::Time::FromInternalValue(password_specifics.date_created()) <= - password_form.date_created) { - *new_password_form = password_form; - return LOCAL; - } - - PasswordFromSpecifics(password_specifics, new_password_form); - return SYNC; -} - -std::string MakePasswordSyncTag(const std::string& origin_url, - const std::string& username_element, - const std::string& username_value, - const std::string& password_element, - const std::string& signon_realm) { - return net::EscapePath(origin_url) + "|" + - net::EscapePath(username_element) + "|" + - net::EscapePath(username_value) + "|" + - net::EscapePath(password_element) + "|" + - net::EscapePath(signon_realm); -} - -std::string MakePasswordSyncTag(const autofill::PasswordForm& password) { - return MakePasswordSyncTag(password.origin.spec(), - base::UTF16ToUTF8(password.username_element), - base::UTF16ToUTF8(password.username_value), - base::UTF16ToUTF8(password.password_element), - password.signon_realm); -} - -syncer::SyncChange::SyncChangeType GetSyncChangeType( - PasswordStoreChange::Type type) { - switch (type) { - case PasswordStoreChange::ADD: - return syncer::SyncChange::ACTION_ADD; - case PasswordStoreChange::UPDATE: - return syncer::SyncChange::ACTION_UPDATE; - case PasswordStoreChange::REMOVE: - return syncer::SyncChange::ACTION_DELETE; - } - NOTREACHED(); - return syncer::SyncChange::ACTION_INVALID; -} - -void AppendChanges(const PasswordStoreChangeList& new_changes, - PasswordStoreChangeList* all_changes) { - all_changes->insert(all_changes->end(), - new_changes.begin(), - new_changes.end()); -} - -} // namespace - -PasswordSyncableService::PasswordSyncableService( - scoped_refptr<PasswordStore> password_store) - : password_store_(password_store) { -} - -PasswordSyncableService::~PasswordSyncableService() {} - -syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing( - syncer::ModelType type, - const syncer::SyncDataList& initial_sync_data, - scoped_ptr<syncer::SyncChangeProcessor> sync_processor, - scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { - DCHECK_EQ(syncer::PASSWORDS, type); - syncer::SyncMergeResult merge_result(type); - sync_error_factory_ = sync_error_factory.Pass(); - sync_processor_ = sync_processor.Pass(); - - // We add all the db entries as |new_local_entries| initially. During model - // association entries that match a sync entry will be removed and this list - // will only contain entries that are not in sync. - ScopedVector<autofill::PasswordForm> password_entries; - PasswordEntryMap new_local_entries; - if (!ReadFromPasswordStore(&password_entries, &new_local_entries)) { - DCHECK(sync_error_factory_); - merge_result.set_error(sync_error_factory_->CreateAndUploadError( - FROM_HERE, - "Failed to get passwords from store.")); - return merge_result; - } - - merge_result.set_num_items_before_association(new_local_entries.size()); - - // List that contains the entries that are known only to sync. - ScopedVector<autofill::PasswordForm> new_sync_entries; - - // List that contains the entries that are known to both sync and db but - // have updates in sync. They need to be updated in the passwords db. - ScopedVector<autofill::PasswordForm> updated_sync_entries; - - // Changes from password db that need to be propagated to sync. - syncer::SyncChangeList updated_db_entries; - for (syncer::SyncDataList::const_iterator sync_iter = - initial_sync_data.begin(); - sync_iter != initial_sync_data.end(); ++sync_iter) { - CreateOrUpdateEntry(*sync_iter, - &new_local_entries, - &new_sync_entries, - &updated_sync_entries, - &updated_db_entries); - } - - WriteToPasswordStore(new_sync_entries.get(), - updated_sync_entries.get(), - PasswordForms()); - - merge_result.set_num_items_after_association( - merge_result.num_items_before_association() + new_sync_entries.size()); - - merge_result.set_num_items_added(new_sync_entries.size()); - - merge_result.set_num_items_modified(updated_sync_entries.size()); - - for (PasswordEntryMap::iterator it = new_local_entries.begin(); - it != new_local_entries.end(); - ++it) { - updated_db_entries.push_back( - syncer::SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_ADD, - SyncDataFromPassword(*it->second))); - } - - merge_result.set_error( - sync_processor_->ProcessSyncChanges(FROM_HERE, updated_db_entries)); - return merge_result; -} - -void PasswordSyncableService::StopSyncing(syncer::ModelType type) { - sync_processor_.reset(); - sync_error_factory_.reset(); -} - -syncer::SyncDataList PasswordSyncableService::GetAllSyncData( - syncer::ModelType type) const { - DCHECK_EQ(syncer::PASSWORDS, type); - ScopedVector<autofill::PasswordForm> password_entries; - ReadFromPasswordStore(&password_entries, NULL); - - syncer::SyncDataList sync_data; - for (PasswordForms::iterator it = password_entries.begin(); - it != password_entries.end(); ++it) { - sync_data.push_back(SyncDataFromPassword(**it)); - } - return sync_data; -} - -syncer::SyncError PasswordSyncableService::ProcessSyncChanges( - const tracked_objects::Location& from_here, - const syncer::SyncChangeList& change_list) { - // The |db_entries_map| and associated vectors are filled only in case of - // update change. - PasswordEntryMap db_entries_map; - ScopedVector<autofill::PasswordForm> password_db_entries; - ScopedVector<autofill::PasswordForm> new_sync_entries; - ScopedVector<autofill::PasswordForm> updated_sync_entries; - ScopedVector<autofill::PasswordForm> deleted_entries; - bool has_read_passwords = false; - - for (syncer::SyncChangeList::const_iterator it = change_list.begin(); - it != change_list.end(); - ++it) { - switch (it->change_type()) { - case syncer::SyncChange::ACTION_ADD: { - const sync_pb::EntitySpecifics& specifics = - it->sync_data().GetSpecifics(); - new_sync_entries.push_back(new autofill::PasswordForm); - PasswordFromSpecifics(specifics.password().client_only_encrypted_data(), - new_sync_entries.back()); - break; - } - case syncer::SyncChange::ACTION_UPDATE: { - if (!has_read_passwords) { - if (ReadFromPasswordStore(&password_db_entries, - &db_entries_map)) { - has_read_passwords = true; - } else { - return sync_error_factory_->CreateAndUploadError( - FROM_HERE, - "Failed to get passwords from store."); - } - } - syncer::SyncChangeList sync_changes; - - CreateOrUpdateEntry(it->sync_data(), - &db_entries_map, - &new_sync_entries, - &updated_sync_entries, - &sync_changes); - DCHECK(sync_changes.empty()); - break; - } - - case syncer::SyncChange::ACTION_DELETE: { - const sync_pb::EntitySpecifics& specifics = - it->sync_data().GetSpecifics(); - const sync_pb::PasswordSpecificsData& password_specifics( - specifics.password().client_only_encrypted_data()); - deleted_entries.push_back(new autofill::PasswordForm); - PasswordFromSpecifics(password_specifics, deleted_entries.back()); - break; - } - case syncer::SyncChange::ACTION_INVALID: - return sync_error_factory_->CreateAndUploadError( - FROM_HERE, - "Failed to process sync changes for passwords datatype."); - } - } - WriteToPasswordStore(new_sync_entries.get(), - updated_sync_entries.get(), - deleted_entries.get()); - return syncer::SyncError(); -} - -void PasswordSyncableService::ActOnPasswordStoreChanges( - const PasswordStoreChangeList& local_changes) { - if (!sync_processor_) - return; - syncer::SyncChangeList sync_changes; - for (PasswordStoreChangeList::const_iterator it = local_changes.begin(); - it != local_changes.end(); - ++it) { - sync_changes.push_back( - syncer::SyncChange(FROM_HERE, - GetSyncChangeType(it->type()), - SyncDataFromPassword(it->form()))); - } - sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes); -} - -bool PasswordSyncableService::ReadFromPasswordStore( - ScopedVector<autofill::PasswordForm>* password_entries, - PasswordEntryMap* passwords_entry_map) const { - DCHECK(password_entries); - if (!password_store_->FillAutofillableLogins(&password_entries->get()) || - !password_store_->FillBlacklistLogins(&password_entries->get())) { - // Password store often fails to load passwords. Track failures with UMA. - // (http://crbug.com/249000) - UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", - ModelTypeToHistogramInt(syncer::PASSWORDS), - syncer::MODEL_TYPE_COUNT); - return false; - } - - if (!passwords_entry_map) - return true; - - for (PasswordForms::iterator it = password_entries->begin(); - it != password_entries->end(); ++it) { - autofill::PasswordForm* password_form = *it; - passwords_entry_map->insert( - std::make_pair(MakePasswordSyncTag(*password_form), password_form)); - } - - return true; -} - -void PasswordSyncableService::WriteToPasswordStore( - const PasswordForms& new_entries, - const PasswordForms& updated_entries, - const PasswordForms& deleted_entries) { - PasswordStoreChangeList changes; - for (std::vector<autofill::PasswordForm*>::const_iterator it = - new_entries.begin(); - it != new_entries.end(); - ++it) { - AppendChanges(password_store_->AddLoginImpl(**it), &changes); - } - - for (std::vector<autofill::PasswordForm*>::const_iterator it = - updated_entries.begin(); - it != updated_entries.end(); - ++it) { - AppendChanges(password_store_->UpdateLoginImpl(**it), &changes); - } - - for (std::vector<autofill::PasswordForm*>::const_iterator it = - deleted_entries.begin(); - it != deleted_entries.end(); - ++it) { - AppendChanges(password_store_->RemoveLoginImpl(**it), &changes); - } - - // We have to notify password store observers of the change by hand since - // we use internal password store interfaces to make changes synchronously. - NotifyPasswordStoreOfLoginChanges(changes); -} - -void PasswordSyncableService::NotifyPasswordStoreOfLoginChanges( - const PasswordStoreChangeList& changes) { - password_store_->NotifyLoginsChanged(changes); -} - -void PasswordSyncableService::CreateOrUpdateEntry( - const syncer::SyncData& data, - PasswordEntryMap* umatched_data_from_password_db, - ScopedVector<autofill::PasswordForm>* new_sync_entries, - ScopedVector<autofill::PasswordForm>* updated_sync_entries, - syncer::SyncChangeList* updated_db_entries) { - const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); - const sync_pb::PasswordSpecificsData& password_specifics( - specifics.password().client_only_encrypted_data()); - std::string tag = MakePasswordSyncTag(password_specifics); - - // Check whether the data from sync is already in the password store. - PasswordEntryMap::iterator existing_local_entry_iter = - umatched_data_from_password_db->find(tag); - if (existing_local_entry_iter == umatched_data_from_password_db->end()) { - // The sync data is not in the password store, so we need to create it in - // the password store. Add the entry to the new_entries list. - scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm); - PasswordFromSpecifics(password_specifics, new_password.get()); - new_sync_entries->push_back(new_password.release()); - } else { - // The entry is in password store. If the entries are not identical, then - // the entries need to be merged. - scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm); - switch (MergeLocalAndSyncPasswords(password_specifics, - *existing_local_entry_iter->second, - new_password.get())) { - case IDENTICAL: - break; - case SYNC: - updated_sync_entries->push_back(new_password.release()); - break; - case LOCAL: - updated_db_entries->push_back( - syncer::SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_UPDATE, - SyncDataFromPassword(*new_password))); - break; - } - // Remove the entry from the entry map to indicate a match has been found. - // Entries that remain in the map at the end of associating all sync entries - // will be treated as additions that need to be propagated to sync. - umatched_data_from_password_db->erase(existing_local_entry_iter); - } -} - -syncer::SyncData SyncDataFromPassword( - const autofill::PasswordForm& password_form) { - sync_pb::EntitySpecifics password_data; - sync_pb::PasswordSpecificsData* password_specifics = - password_data.mutable_password()->mutable_client_only_encrypted_data(); - password_specifics->set_scheme(password_form.scheme); - password_specifics->set_signon_realm(password_form.signon_realm); - password_specifics->set_origin(password_form.origin.spec()); - password_specifics->set_action(password_form.action.spec()); - password_specifics->set_username_element( - base::UTF16ToUTF8(password_form.username_element)); - password_specifics->set_password_element( - base::UTF16ToUTF8(password_form.password_element)); - password_specifics->set_username_value( - base::UTF16ToUTF8(password_form.username_value)); - password_specifics->set_password_value( - base::UTF16ToUTF8(password_form.password_value)); - password_specifics->set_ssl_valid(password_form.ssl_valid); - password_specifics->set_preferred(password_form.preferred); - password_specifics->set_date_created( - password_form.date_created.ToInternalValue()); - password_specifics->set_blacklisted(password_form.blacklisted_by_user); - - std::string tag = MakePasswordSyncTag(*password_specifics); - return syncer::SyncData::CreateLocalData(tag, tag, password_data); -} - -void PasswordFromSpecifics(const sync_pb::PasswordSpecificsData& password, - autofill::PasswordForm* new_password) { - new_password->scheme = - static_cast<autofill::PasswordForm::Scheme>(password.scheme()); - new_password->signon_realm = password.signon_realm(); - new_password->origin = GURL(password.origin()); - new_password->action = GURL(password.action()); - new_password->username_element = - base::UTF8ToUTF16(password.username_element()); - new_password->password_element = - base::UTF8ToUTF16(password.password_element()); - new_password->username_value = base::UTF8ToUTF16(password.username_value()); - new_password->password_value = base::UTF8ToUTF16(password.password_value()); - new_password->ssl_valid = password.ssl_valid(); - new_password->preferred = password.preferred(); - new_password->date_created = - base::Time::FromInternalValue(password.date_created()); - new_password->blacklisted_by_user = password.blacklisted(); -} - -std::string MakePasswordSyncTag( - const sync_pb::PasswordSpecificsData& password) { - return MakePasswordSyncTag(password.origin(), - password.username_element(), - password.username_value(), - password.password_element(), - password.signon_realm()); -} diff --git a/chrome/browser/password_manager/password_syncable_service.h b/chrome/browser/password_manager/password_syncable_service.h deleted file mode 100644 index 38e8ef3..0000000 --- a/chrome/browser/password_manager/password_syncable_service.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2013 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. - -#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ -#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ - -#include <string> -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "components/password_manager/core/browser/password_store_change.h" -#include "sync/api/sync_change.h" -#include "sync/api/sync_data.h" -#include "sync/api/sync_error.h" -#include "sync/api/syncable_service.h" -#include "sync/protocol/password_specifics.pb.h" -#include "sync/protocol/sync.pb.h" - -namespace autofill { -struct PasswordForm; -} - -namespace syncer { -class SyncErrorFactory; -} - -class PasswordStore; - -class PasswordSyncableService : public syncer::SyncableService { - public: - // TODO(lipalani) - The |PasswordStore| should outlive - // |PasswordSyncableService| and there should be a code - // guarantee to that effect. Currently this object is not instantiated. - // When this class is completed and instantiated the object lifetime - // guarantee will be implemented. - explicit PasswordSyncableService( - scoped_refptr<PasswordStore> password_store); - virtual ~PasswordSyncableService(); - - // syncer::SyncableServiceImplementations - virtual syncer::SyncMergeResult MergeDataAndStartSyncing( - syncer::ModelType type, - const syncer::SyncDataList& initial_sync_data, - scoped_ptr<syncer::SyncChangeProcessor> sync_processor, - scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE; - virtual void StopSyncing(syncer::ModelType type) OVERRIDE; - virtual syncer::SyncDataList GetAllSyncData( - syncer::ModelType type) const OVERRIDE; - virtual syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& from_here, - const syncer::SyncChangeList& change_list) OVERRIDE; - - // Notifies sync of changes to the password database. - void ActOnPasswordStoreChanges(const PasswordStoreChangeList& changes); - - private: - typedef std::vector<autofill::PasswordForm*> PasswordForms; - // Map from password sync tag to password form. - typedef std::map<std::string, autofill::PasswordForm*> PasswordEntryMap; - - // Helper function to retrieve the entries from password db and fill both - // |password_entries| and |passwords_entry_map|. |passwords_entry_map| can be - // NULL. - bool ReadFromPasswordStore( - ScopedVector<autofill::PasswordForm>* password_entries, - PasswordEntryMap* passwords_entry_map) const; - - // Uses the |PasswordStore| APIs to change entries. - void WriteToPasswordStore(const PasswordForms& new_entries, - const PasswordForms& updated_entries, - const PasswordForms& deleted_entries); - - // Notifies password store of a change that was performed by sync. - // Virtual so tests can override. - virtual void NotifyPasswordStoreOfLoginChanges( - const PasswordStoreChangeList& changes); - - // Checks if |data|, the entry in sync db, needs to be created or updated - // in the passwords db. Depending on what action needs to be performed, the - // entry may be added to |new_sync_entries| or to |updated_sync_entries|. If - // the item is identical to an entry in the passwords db, no action is - // performed. If an item needs to be updated in the sync db, then the item is - // also added to |updated_db_entries| list. If |data|'s tag is identical to - // an entry's tag in |umatched_data_from_password_db| then that entry will be - // removed from |umatched_data_from_password_db|. - void CreateOrUpdateEntry( - const syncer::SyncData& data, - PasswordEntryMap* umatched_data_from_password_db, - ScopedVector<autofill::PasswordForm>* new_sync_entries, - ScopedVector<autofill::PasswordForm>* updated_sync_entries, - syncer::SyncChangeList* updated_db_entries); - - // The factory that creates sync errors. |SyncError| has rich data - // suitable for debugging. - scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_; - - // |SyncProcessor| will mirror the |PasswordStore| changes in the sync db. - scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; - - // The password store that adds/updates/deletes password entries. - scoped_refptr<PasswordStore> password_store_; -}; - -// Converts the |password| into a SyncData object. -syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); - -// Extracts the |PasswordForm| data from sync's protobuffer format. -void PasswordFromSpecifics(const sync_pb::PasswordSpecificsData& password, - autofill::PasswordForm* new_password); - -// Returns the unique tag that will serve as the sync identifier for the -// |password| entry. -std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); - -#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ diff --git a/chrome/browser/password_manager/password_syncable_service_unittest.cc b/chrome/browser/password_manager/password_syncable_service_unittest.cc deleted file mode 100644 index 98a36af..0000000 --- a/chrome/browser/password_manager/password_syncable_service_unittest.cc +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright 2014 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. - -#include "chrome/browser/password_manager/password_syncable_service.h" - -#include <algorithm> -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "components/password_manager/core/browser/mock_password_store.h" -#include "sync/api/sync_change_processor.h" -#include "sync/api/sync_error.h" -#include "sync/api/sync_error_factory.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using syncer::SyncChange; -using syncer::SyncData; -using syncer::SyncDataList; -using syncer::SyncError; -using testing::Invoke; -using testing::Return; -using testing::SetArgPointee; -using testing::_; - -namespace { - -typedef std::vector<SyncChange> SyncChangeList; - -const sync_pb::PasswordSpecificsData& GetPasswordSpecifics( - const syncer::SyncData& sync_data) { - const sync_pb::EntitySpecifics& specifics = sync_data.GetSpecifics(); - return specifics.password().client_only_encrypted_data(); -} - -void PasswordsEqual(const sync_pb::PasswordSpecificsData& expected_password, - const sync_pb::PasswordSpecificsData& actual_password) { - EXPECT_EQ(expected_password.scheme(), actual_password.scheme()); - EXPECT_EQ(expected_password.signon_realm(), actual_password.signon_realm()); - EXPECT_EQ(expected_password.origin(), actual_password.origin()); - EXPECT_EQ(expected_password.action(), actual_password.action()); - EXPECT_EQ(expected_password.username_element(), - actual_password.username_element()); - EXPECT_EQ(expected_password.password_element(), - actual_password.password_element()); - EXPECT_EQ(expected_password.username_value(), - actual_password.username_value()); - EXPECT_EQ(expected_password.password_value(), - actual_password.password_value()); - EXPECT_EQ(expected_password.ssl_valid(), actual_password.ssl_valid()); - EXPECT_EQ(expected_password.preferred(), actual_password.preferred()); - EXPECT_EQ(expected_password.date_created(), actual_password.date_created()); - EXPECT_EQ(expected_password.blacklisted(), actual_password.blacklisted()); -} - -// Creates a sync data consisting of password specifics. The sign on realm is -// set to |signon_realm|. -SyncData CreateSyncData(const std::string& signon_realm) { - sync_pb::EntitySpecifics password_data; - sync_pb::PasswordSpecificsData* password_specifics = - password_data.mutable_password()->mutable_client_only_encrypted_data(); - password_specifics->set_signon_realm(signon_realm); - - std::string tag = MakePasswordSyncTag(*password_specifics); - return syncer::SyncData::CreateLocalData(tag, tag, password_data); -} - -SyncChange CreateSyncChange(const autofill::PasswordForm& password, - SyncChange::SyncChangeType type) { - SyncData data = SyncDataFromPassword(password); - return SyncChange(FROM_HERE, type, data); -} - -// A testable implementation of the |PasswordSyncableService| that mocks -// out all interaction with the password database. -class MockPasswordSyncableService : public PasswordSyncableService { - public: - explicit MockPasswordSyncableService(PasswordStore* password_store) - : PasswordSyncableService(password_store) {} - virtual ~MockPasswordSyncableService() {} - - MOCK_METHOD1(NotifyPasswordStoreOfLoginChanges, - void (const PasswordStoreChangeList&)); -}; - -// Class to verify the arguments passed to |PasswordStore|. -class PasswordStoreDataVerifier { - public: - PasswordStoreDataVerifier() {} - ~PasswordStoreDataVerifier() { - EXPECT_TRUE(expected_db_add_changes_.empty()); - EXPECT_TRUE(expected_db_update_changes_.empty()); - EXPECT_TRUE(expected_db_delete_changes_.empty()); - } - - class TestSyncChangeProcessor; - - // Sets expected changes to the password database. - void SetExpectedDBChanges( - const SyncDataList& add_forms, - const std::vector<autofill::PasswordForm*>& update_forms, - const std::vector<autofill::PasswordForm*>& delete_forms, - MockPasswordStore* password_store); - // Sets expected changes to TestSyncChangeProcessor. - void SetExpectedSyncChanges(SyncChangeList list); - - private: - // Checks that |change_list| matches |expected_sync_change_list_|. - SyncError TestSyncChanges(const SyncChangeList& change_list); - - // Verifies that the |password| is present in the |expected_db_add_changes_| - // list. If found, |password| would be removed from - // |expected_db_add_changes_| list. - PasswordStoreChangeList VerifyAdd(const autofill::PasswordForm& password) { - return VerifyChange(PasswordStoreChange::ADD, password, - &expected_db_add_changes_); - } - - // Verifies that the |password| is present in the - // |expected_db_update_changes_| list. If found, |password| would be removed - // from |expected_db_update_changes_| list. - PasswordStoreChangeList VerifyUpdate(const autofill::PasswordForm& password) { - return VerifyChange(PasswordStoreChange::UPDATE, password, - &expected_db_update_changes_); - } - - // Verifies that the |password| is present in the - // |expected_db_delete_changes_| list. If found, |password| would be removed - // from |expected_db_delete_changes_| list. - PasswordStoreChangeList VerifyDelete(const autofill::PasswordForm& password) { - return VerifyChange(PasswordStoreChange::REMOVE, password, - &expected_db_delete_changes_); - } - - static PasswordStoreChangeList VerifyChange( - PasswordStoreChange::Type type, - const autofill::PasswordForm& password, - std::vector<autofill::PasswordForm>* password_list); - - std::vector<autofill::PasswordForm> expected_db_add_changes_; - std::vector<autofill::PasswordForm> expected_db_update_changes_; - std::vector<autofill::PasswordForm> expected_db_delete_changes_; - SyncChangeList expected_sync_change_list_; - - DISALLOW_COPY_AND_ASSIGN(PasswordStoreDataVerifier); -}; - -class PasswordStoreDataVerifier::TestSyncChangeProcessor - : public syncer::SyncChangeProcessor { - public: - explicit TestSyncChangeProcessor(PasswordStoreDataVerifier* verifier) - : verifier_(verifier) { - } - virtual ~TestSyncChangeProcessor() {} - - virtual SyncError ProcessSyncChanges(const tracked_objects::Location&, - const SyncChangeList& list) OVERRIDE { - return verifier_->TestSyncChanges(list); - } - - virtual SyncDataList GetAllSyncData(syncer::ModelType type) const OVERRIDE { - return SyncDataList(); - } - private: - PasswordStoreDataVerifier* verifier_; - - DISALLOW_COPY_AND_ASSIGN(TestSyncChangeProcessor); -}; - -void PasswordStoreDataVerifier::SetExpectedDBChanges( - const SyncDataList& add_forms, - const std::vector<autofill::PasswordForm*>& update_forms, - const std::vector<autofill::PasswordForm*>& delete_forms, - MockPasswordStore* password_store) { - DCHECK(expected_db_add_changes_.empty()); - DCHECK(expected_db_update_changes_.empty()); - DCHECK(password_store); - - for (SyncDataList::const_iterator it = add_forms.begin(); - it != add_forms.end(); ++it) { - autofill::PasswordForm form; - PasswordFromSpecifics(GetPasswordSpecifics(*it), &form); - expected_db_add_changes_.push_back(form); - } - if (expected_db_add_changes_.empty()) { - EXPECT_CALL(*password_store, AddLoginImpl(_)).Times(0); - } else { - EXPECT_CALL(*password_store, AddLoginImpl(_)) - .Times(expected_db_add_changes_.size()) - .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyAdd)); - } - - for (std::vector<autofill::PasswordForm*>::const_iterator it = - update_forms.begin(); - it != update_forms.end(); ++it) { - expected_db_update_changes_.push_back(**it); - } - if (expected_db_update_changes_.empty()) { - EXPECT_CALL(*password_store, UpdateLoginImpl(_)).Times(0); - } else { - EXPECT_CALL(*password_store, UpdateLoginImpl(_)) - .Times(expected_db_update_changes_.size()) - .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyUpdate)); - } - - for (std::vector<autofill::PasswordForm*>::const_iterator it = - delete_forms.begin(); - it != delete_forms.end(); ++it) { - expected_db_delete_changes_.push_back(**it); - } - if (expected_db_delete_changes_.empty()) { - EXPECT_CALL(*password_store, RemoveLoginImpl(_)).Times(0); - } else { - EXPECT_CALL(*password_store, RemoveLoginImpl(_)) - .Times(expected_db_delete_changes_.size()) - .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyDelete)); - } -} - -void PasswordStoreDataVerifier::SetExpectedSyncChanges(SyncChangeList list) { - expected_sync_change_list_.swap(list); -} - -SyncError PasswordStoreDataVerifier::TestSyncChanges( - const SyncChangeList& change_list) { - for (SyncChangeList::const_iterator it = change_list.begin(); - it != change_list.end(); ++it) { - const SyncChange& data = *it; - const sync_pb::PasswordSpecificsData& actual_password( - GetPasswordSpecifics(data.sync_data())); - std::string actual_tag = MakePasswordSyncTag(actual_password); - - bool matched = false; - for (SyncChangeList::iterator expected_it = - expected_sync_change_list_.begin(); - expected_it != expected_sync_change_list_.end(); - ++expected_it) { - const sync_pb::PasswordSpecificsData& expected_password( - GetPasswordSpecifics(expected_it->sync_data())); - if (actual_tag == MakePasswordSyncTag(expected_password)) { - PasswordsEqual(expected_password, actual_password); - EXPECT_EQ(expected_it->change_type(), data.change_type()); - matched = true; - break; - } - } - EXPECT_TRUE(matched) << actual_tag; - } - EXPECT_EQ(expected_sync_change_list_.size(), change_list.size()); - return SyncError(); -} - -// static -PasswordStoreChangeList PasswordStoreDataVerifier::VerifyChange( - PasswordStoreChange::Type type, - const autofill::PasswordForm& password, - std::vector<autofill::PasswordForm>* password_list) { - std::vector<autofill::PasswordForm>::iterator it = - std::find(password_list->begin(), password_list->end(), password); - EXPECT_NE(password_list->end(), it); - password_list->erase(it); - return PasswordStoreChangeList(1, PasswordStoreChange(type, password)); -} - -class PasswordSyncableServiceWrapper { - public: - PasswordSyncableServiceWrapper() { - password_store_ = new MockPasswordStore; - service_.reset(new MockPasswordSyncableService(password_store_)); - } - - ~PasswordSyncableServiceWrapper() { - password_store_->Shutdown(); - } - - MockPasswordStore* password_store() { - return password_store_; - } - - MockPasswordSyncableService* service() { - return service_.get(); - } - - // Returnes the scoped_ptr to |service_| thus NULLing out it. - scoped_ptr<syncer::SyncChangeProcessor> ReleaseSyncableService() { - return service_.PassAs<syncer::SyncChangeProcessor>(); - } - - PasswordStoreDataVerifier* verifier() { - return &verifier_; - } - - scoped_ptr<syncer::SyncChangeProcessor> CreateSyncChangeProcessor() { - return make_scoped_ptr<syncer::SyncChangeProcessor>( - new PasswordStoreDataVerifier::TestSyncChangeProcessor(verifier())); - } - - // Sets the data that will be returned to the caller accessing password store. - void SetPasswordStoreData( - const std::vector<autofill::PasswordForm*>& forms, - const std::vector<autofill::PasswordForm*>& blacklist_forms) { - EXPECT_CALL(*password_store_, FillAutofillableLogins(_)) - .WillOnce(Invoke(AppendVector(forms))) - .RetiresOnSaturation(); - EXPECT_CALL(*password_store_, FillBlacklistLogins(_)) - .WillOnce(Invoke(AppendVector(blacklist_forms))) - .RetiresOnSaturation(); - } - - protected: - scoped_refptr<MockPasswordStore> password_store_; - scoped_ptr<MockPasswordSyncableService> service_; - PasswordStoreDataVerifier verifier_; - - private: - struct AppendVector { - explicit AppendVector( - const std::vector<autofill::PasswordForm*>& append_forms) - : append_forms_(append_forms) { - } - - ~AppendVector() {} - - bool operator()(std::vector<autofill::PasswordForm*>* forms) const { - forms->insert(forms->end(), append_forms_.begin(), append_forms_.end()); - return true; - } - - std::vector<autofill::PasswordForm*> append_forms_; - }; - - DISALLOW_COPY_AND_ASSIGN(PasswordSyncableServiceWrapper); -}; - -class PasswordSyncableServiceTest : public testing::Test, - public PasswordSyncableServiceWrapper { - public: - PasswordSyncableServiceTest() {} - virtual ~PasswordSyncableServiceTest() {} -}; - - -// Both sync and password db have data that are not present in the other. -TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - std::vector<autofill::PasswordForm*> forms; - forms.push_back(form1.release()); - SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>()); - - SyncData sync_data = CreateSyncData("def"); - SyncDataList list; - list.push_back(sync_data); - - verifier()->SetExpectedDBChanges(list, - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges( - SyncChangeList(1, CreateSyncChange(*forms[0], SyncChange::ACTION_ADD))); - EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_)); - - service()->MergeDataAndStartSyncing(syncer::PASSWORDS, - list, - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -// Sync has data that is not present in the password db. -TEST_F(PasswordSyncableServiceTest, AdditionOnlyInSync) { - SetPasswordStoreData(std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>()); - - SyncData sync_data = CreateSyncData("def"); - SyncDataList list; - list.push_back(sync_data); - - verifier()->SetExpectedDBChanges(list, - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges(SyncChangeList()); - EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_)); - - service()->MergeDataAndStartSyncing(syncer::PASSWORDS, - list, - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -// Passwords db has data that is not present in sync. -TEST_F(PasswordSyncableServiceTest, AdditionOnlyInPasswordStore) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - std::vector<autofill::PasswordForm*> forms; - forms.push_back(form1.release()); - SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>()); - - verifier()->SetExpectedDBChanges(SyncDataList(), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges( - SyncChangeList(1, CreateSyncChange(*forms[0], SyncChange::ACTION_ADD))); - EXPECT_CALL(*service_, - NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList())); - - service()->MergeDataAndStartSyncing(syncer::PASSWORDS, - SyncDataList(), - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -// Both passwords db and sync contain the same data. -TEST_F(PasswordSyncableServiceTest, BothInSync) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - std::vector<autofill::PasswordForm*> forms; - forms.push_back(form1.release()); - SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>()); - - verifier()->SetExpectedDBChanges(SyncDataList(), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges(SyncChangeList()); - EXPECT_CALL(*service_, - NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList())); - - service()->MergeDataAndStartSyncing(syncer::PASSWORDS, - SyncDataList(1, CreateSyncData("abc")), - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -// Both passwords db and sync have the same data but they need to be merged -// as some fields of the data differ. -TEST_F(PasswordSyncableServiceTest, Merge) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - form1->action = GURL("http://pie.com"); - form1->date_created = base::Time::Now(); - std::vector<autofill::PasswordForm*> forms; - forms.push_back(form1.release()); - SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>()); - - verifier()->SetExpectedDBChanges(SyncDataList(), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges( - SyncChangeList(1, CreateSyncChange(*forms[0], - SyncChange::ACTION_UPDATE))); - - EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_)); - - service()->MergeDataAndStartSyncing(syncer::PASSWORDS, - SyncDataList(1, CreateSyncData("abc")), - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -// Initiate sync due to local DB changes. -TEST_F(PasswordSyncableServiceTest, PasswordStoreChanges) { - // Set the sync change processor first. - SetPasswordStoreData(std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>()); - verifier()->SetExpectedSyncChanges(SyncChangeList()); - EXPECT_CALL(*service_, - NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList())); - service_->MergeDataAndStartSyncing(syncer::PASSWORDS, - SyncDataList(), - CreateSyncChangeProcessor(), - scoped_ptr<syncer::SyncErrorFactory>()); - - autofill::PasswordForm form1; - form1.signon_realm = "abc"; - autofill::PasswordForm form2; - form2.signon_realm = "def"; - autofill::PasswordForm form3; - form3.signon_realm = "xyz"; - - SyncChangeList sync_list; - sync_list.push_back(CreateSyncChange(form1, SyncChange::ACTION_ADD)); - sync_list.push_back(CreateSyncChange(form2, SyncChange::ACTION_UPDATE)); - sync_list.push_back(CreateSyncChange(form3, SyncChange::ACTION_DELETE)); - - verifier()->SetExpectedDBChanges(SyncDataList(), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - verifier()->SetExpectedSyncChanges(sync_list); - - PasswordStoreChangeList list; - list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form1)); - list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form2)); - list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form3)); - service()->ActOnPasswordStoreChanges(list); -} - -// Process all types of changes from sync. -TEST_F(PasswordSyncableServiceTest, ProcessSyncChanges) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - form1->action = GURL("http://foo.com"); - scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm); - form2->signon_realm = "xyz"; - form2->action = GURL("http://bar.com"); - form2->date_created = base::Time::Now(); - form2->blacklisted_by_user = true; - std::vector<autofill::PasswordForm*> forms(1, form1.release()); - std::vector<autofill::PasswordForm*> blacklist_forms(1, form2.release()); - SetPasswordStoreData(forms, blacklist_forms); - - SyncData add_data = CreateSyncData("def"); - autofill::PasswordForm updated_form = *forms[0]; - updated_form.date_created = base::Time::Now(); - std::vector<autofill::PasswordForm*> updated_passwords(1, &updated_form); - std::vector<autofill::PasswordForm*> deleted_passwords(1, blacklist_forms[0]); - verifier()->SetExpectedDBChanges(SyncDataList(1, add_data), - updated_passwords, - deleted_passwords, - password_store()); - - SyncChangeList list; - list.push_back(SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_ADD, - add_data)); - list.push_back(SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_UPDATE, - SyncDataFromPassword(updated_form))); - list.push_back(CreateSyncChange(*blacklist_forms[0], - syncer::SyncChange::ACTION_DELETE)); - EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_)); - service()->ProcessSyncChanges(FROM_HERE, list); -} - -// Retrives sync data from the model. -TEST_F(PasswordSyncableServiceTest, GetAllSyncData) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - form1->action = GURL("http://foo.com"); - scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm); - form2->signon_realm = "xyz"; - form2->action = GURL("http://bar.com"); - form2->blacklisted_by_user = true; - std::vector<autofill::PasswordForm*> forms(1, form1.release()); - std::vector<autofill::PasswordForm*> blacklist_forms(1, form2.release()); - SetPasswordStoreData(forms, blacklist_forms); - - SyncDataList expected_list; - expected_list.push_back(SyncDataFromPassword(*forms[0])); - expected_list.push_back(SyncDataFromPassword(*blacklist_forms[0])); - - verifier()->SetExpectedDBChanges(SyncDataList(), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - - SyncDataList actual_list = service()->GetAllSyncData(syncer::PASSWORDS); - EXPECT_EQ(expected_list.size(), actual_list.size()); - for (SyncDataList::iterator i(actual_list.begin()), j(expected_list.begin()); - i != actual_list.end() && j != expected_list.end(); ++i, ++j) { - PasswordsEqual(GetPasswordSpecifics(*j), GetPasswordSpecifics(*i)); - } -} - -// Creates 2 PasswordSyncableService instances, merges the content of the first -// one to the second one and back. -TEST_F(PasswordSyncableServiceTest, MergeDataAndPushBack) { - scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm); - form1->signon_realm = "abc"; - form1->action = GURL("http://foo.com"); - std::vector<autofill::PasswordForm*> forms(1, form1.release()); - SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>()); - - PasswordSyncableServiceWrapper other_service_wrapper; - scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm); - form2->signon_realm = "xyz"; - form2->action = GURL("http://bar.com"); - syncer::SyncData form2_sync_data = SyncDataFromPassword(*form2); - other_service_wrapper.SetPasswordStoreData( - std::vector<autofill::PasswordForm*>(1, form2.release()), - std::vector<autofill::PasswordForm*>()); - - verifier()->SetExpectedDBChanges(SyncDataList(1, form2_sync_data), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - password_store()); - other_service_wrapper.verifier()->SetExpectedDBChanges( - SyncDataList(1, SyncDataFromPassword(*forms[0])), - std::vector<autofill::PasswordForm*>(), - std::vector<autofill::PasswordForm*>(), - other_service_wrapper.password_store()); - EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_)); - EXPECT_CALL(*other_service_wrapper.service(), - NotifyPasswordStoreOfLoginChanges(_)); - - syncer::SyncDataList other_service_data = - other_service_wrapper.service()->GetAllSyncData(syncer::PASSWORDS); - service()->MergeDataAndStartSyncing( - syncer::PASSWORDS, - other_service_data, - other_service_wrapper.ReleaseSyncableService(), - scoped_ptr<syncer::SyncErrorFactory>()); -} - -} // namespace |