summaryrefslogtreecommitdiff
path: root/chromium/components/password_manager/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-15 14:18:00 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-15 14:00:37 +0000
commit66a2147d838e293f4a5db7711c8eba4e6faaaf0f (patch)
tree61ad99912355f5b6cc603d9b1dfadd77b950ce98 /chromium/components/password_manager/core
parentda51f56cc21233c2d30f0fe0d171727c3102b2e0 (diff)
downloadqtwebengine-chromium-66a2147d838e293f4a5db7711c8eba4e6faaaf0f.tar.gz
BASELINE: Update Chromium to 65.0.3325.75
Change-Id: I5485bc5c111539356276457516584fa5737f07d8 Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'chromium/components/password_manager/core')
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service.cc406
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service.h29
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc567
3 files changed, 63 insertions, 939 deletions
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service.cc b/chromium/components/password_manager/core/browser/password_syncable_service.cc
index 4653ac0cf8b..4f959a6ba44 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service.cc
@@ -12,12 +12,8 @@
#include "base/auto_reset.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
-#include "base/optional.h"
-#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/time/default_clock.h"
#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store_sync.h"
#include "components/sync/model/sync_error_factory.h"
@@ -40,12 +36,20 @@ std::string MakePasswordSyncTag(const autofill::PasswordForm& password);
namespace {
// Returns true iff |password_specifics| and |password_specifics| are equal
-// in the fields which don't comprise the sync tag.
-bool AreLocalAndSyncPasswordsNonSyncTagEqual(
+// memberwise.
+bool AreLocalAndSyncPasswordsEqual(
const sync_pb::PasswordSpecificsData& password_specifics,
const autofill::PasswordForm& password_form) {
return (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.preferred == password_specifics.preferred() &&
@@ -62,38 +66,6 @@ bool AreLocalAndSyncPasswordsNonSyncTagEqual(
.Serialize() == password_form.federation_origin.Serialize());
}
-// Returns true iff |password_specifics| and |password_specifics| are equal
-// memberwise.
-bool AreLocalAndSyncPasswordsEqual(
- const sync_pb::PasswordSpecificsData& password_specifics,
- const autofill::PasswordForm& password_form) {
- return (password_form.signon_realm == password_specifics.signon_realm() &&
- password_form.origin.spec() == password_specifics.origin() &&
- 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() &&
- AreLocalAndSyncPasswordsNonSyncTagEqual(password_specifics,
- password_form));
-}
-
-// Compares the fields which are not part of the sync tag.
-bool AreNonSyncTagFieldsEqual(const sync_pb::PasswordSpecificsData& left,
- const sync_pb::PasswordSpecificsData& right) {
- return (left.scheme() == right.scheme() && left.action() == right.action() &&
- left.password_value() == right.password_value() &&
- left.preferred() == right.preferred() &&
- left.date_created() == right.date_created() &&
- left.blacklisted() == right.blacklisted() &&
- left.type() == right.type() &&
- left.times_used() == right.times_used() &&
- left.display_name() == right.display_name() &&
- left.avatar_url() == right.avatar_url() &&
- left.federation_url() == right.federation_url());
-}
-
syncer::SyncChange::SyncChangeType GetSyncChangeType(
PasswordStoreChange::Type type) {
switch (type) {
@@ -119,190 +91,6 @@ void AppendPasswordFromSpecifics(
entries->back()->date_synced = sync_time;
}
-// Android autofill saves credential in a different format without trailing '/'.
-std::string GetIncorrectAndroidSignonRealm(std::string android_autofill_realm) {
- if (base::EndsWith(android_autofill_realm, "/", base::CompareCase::SENSITIVE))
- android_autofill_realm.erase(android_autofill_realm.size() - 1);
- return android_autofill_realm;
-}
-
-// The correct Android signon_realm should have a trailing '/'.
-std::string GetCorrectAndroidSignonRealm(std::string android_realm) {
- if (!base::EndsWith(android_realm, "/", base::CompareCase::SENSITIVE))
- android_realm += '/';
- return android_realm;
-}
-
-// Android autofill saves credentials in a different format without trailing
-// '/'. Return a sync tag for the style used by Android Autofill in GMS Core
-// v12.
-std::string AndroidAutofillSyncTag(
- const sync_pb::PasswordSpecificsData& password) {
- // realm has the same value as the origin.
- std::string origin = GetIncorrectAndroidSignonRealm(password.origin());
- std::string signon_realm =
- GetIncorrectAndroidSignonRealm(password.signon_realm());
- return (net::EscapePath(origin) + "|" +
- net::EscapePath(password.username_element()) + "|" +
- net::EscapePath(password.username_value()) + "|" +
- net::EscapePath(password.password_element()) + "|" +
- net::EscapePath(signon_realm));
-}
-
-// Return a sync tag for the correct format used by Android.
-std::string AndroidCorrectSyncTag(
- const sync_pb::PasswordSpecificsData& password) {
- // realm has the same value as the origin.
- std::string origin = GetCorrectAndroidSignonRealm(password.origin());
- std::string signon_realm =
- GetCorrectAndroidSignonRealm(password.signon_realm());
- return (net::EscapePath(origin) + "|" +
- net::EscapePath(password.username_element()) + "|" +
- net::EscapePath(password.username_value()) + "|" +
- net::EscapePath(password.password_element()) + "|" +
- net::EscapePath(signon_realm));
-}
-
-void PasswordSpecificsFromPassword(
- const autofill::PasswordForm& password_form,
- sync_pb::PasswordSpecificsData* password_specifics) {
-#define CopyField(field) password_specifics->set_##field(password_form.field)
-#define CopyStringField(field) \
- password_specifics->set_##field(base::UTF16ToUTF8(password_form.field))
- CopyField(scheme);
- CopyField(signon_realm);
- password_specifics->set_origin(password_form.origin.spec());
- password_specifics->set_action(password_form.action.spec());
- CopyStringField(username_element);
- CopyStringField(password_element);
- CopyStringField(username_value);
- CopyStringField(password_value);
- CopyField(preferred);
- password_specifics->set_date_created(
- password_form.date_created.ToInternalValue());
- password_specifics->set_blacklisted(password_form.blacklisted_by_user);
- CopyField(type);
- CopyField(times_used);
- CopyStringField(display_name);
- password_specifics->set_avatar_url(password_form.icon_url.spec());
- password_specifics->set_federation_url(
- password_form.federation_origin.unique()
- ? std::string()
- : password_form.federation_origin.Serialize());
-#undef CopyStringField
-#undef CopyField
-}
-
-struct AndroidMergeResult {
- // New value for Android entry in the correct format.
- base::Optional<syncer::SyncData> new_android_correct;
- // New value for Android autofill entry.
- base::Optional<syncer::SyncData> new_android_incorrect;
- // New value for local entry in the correct format.
- base::Optional<autofill::PasswordForm> new_local_correct;
- // New value for local entry in the Android autofill format.
- base::Optional<autofill::PasswordForm> new_local_incorrect;
-};
-
-// Perform deduplication of Android credentials saved in the wrong format. As
-// the result all the four entries should be created and have the same value.
-AndroidMergeResult Perform4WayMergeAndroidCredentials(
- const sync_pb::PasswordSpecificsData* correct_android,
- const sync_pb::PasswordSpecificsData* incorrect_android,
- const autofill::PasswordForm* correct_local,
- const autofill::PasswordForm* incorrect_local) {
- AndroidMergeResult result;
-
- base::Optional<sync_pb::PasswordSpecificsData> local_correct_ps;
- if (correct_local) {
- local_correct_ps = sync_pb::PasswordSpecificsData();
- PasswordSpecificsFromPassword(*correct_local, &local_correct_ps.value());
- }
-
- base::Optional<sync_pb::PasswordSpecificsData> local_incorrect_ps;
- if (incorrect_local) {
- local_incorrect_ps = sync_pb::PasswordSpecificsData();
- PasswordSpecificsFromPassword(*incorrect_local,
- &local_incorrect_ps.value());
- }
-
- const sync_pb::PasswordSpecificsData* all_data[4] = {
- correct_android, incorrect_android,
- local_correct_ps ? &local_correct_ps.value() : nullptr,
- local_incorrect_ps ? &local_incorrect_ps.value() : nullptr};
-
- // |newest_data| will point to the newest entry out of all 4.
- const sync_pb::PasswordSpecificsData* newest_data = nullptr;
- for (int i = 0; i < 4; ++i) {
- if (newest_data && all_data[i]) {
- if (all_data[i]->date_created() > newest_data->date_created())
- newest_data = all_data[i];
- } else if (all_data[i]) {
- newest_data = all_data[i];
- }
- }
- DCHECK(newest_data);
-
- const std::string correct_tag = AndroidCorrectSyncTag(*newest_data);
- const std::string incorrect_tag = AndroidAutofillSyncTag(*newest_data);
- const std::string correct_signon_realm =
- GetCorrectAndroidSignonRealm(newest_data->signon_realm());
- const std::string incorrect_signon_realm =
- GetIncorrectAndroidSignonRealm(newest_data->signon_realm());
- const std::string correct_origin =
- GetCorrectAndroidSignonRealm(newest_data->origin());
- const std::string incorrect_origin =
- GetIncorrectAndroidSignonRealm(newest_data->origin());
- DCHECK_EQ(GURL(incorrect_origin).spec(), incorrect_origin);
-
- // Set the correct Sync entry if needed.
- if (newest_data != correct_android &&
- (!correct_android ||
- !AreNonSyncTagFieldsEqual(*correct_android, *newest_data))) {
- sync_pb::EntitySpecifics password_data;
- sync_pb::PasswordSpecificsData* password_specifics =
- password_data.mutable_password()->mutable_client_only_encrypted_data();
- *password_specifics = *newest_data;
- password_specifics->set_origin(correct_origin);
- password_specifics->set_signon_realm(correct_signon_realm);
- result.new_android_correct = syncer::SyncData::CreateLocalData(
- correct_tag, correct_tag, password_data);
- }
-
- // Set the Andoroid Autofill Sync entry if needed.
- if (newest_data != incorrect_android &&
- (!incorrect_android ||
- !AreNonSyncTagFieldsEqual(*incorrect_android, *newest_data))) {
- sync_pb::EntitySpecifics password_data;
- sync_pb::PasswordSpecificsData* password_specifics =
- password_data.mutable_password()->mutable_client_only_encrypted_data();
- *password_specifics = *newest_data;
- password_specifics->set_origin(incorrect_origin);
- password_specifics->set_signon_realm(incorrect_signon_realm);
- result.new_android_incorrect = syncer::SyncData::CreateLocalData(
- incorrect_tag, incorrect_tag, password_data);
- }
-
- // Set the correct local entry if needed.
- if (!local_correct_ps ||
- (newest_data != &local_correct_ps.value() &&
- !AreNonSyncTagFieldsEqual(local_correct_ps.value(), *newest_data))) {
- result.new_local_correct = PasswordFromSpecifics(*newest_data);
- result.new_local_correct.value().origin = GURL(correct_origin);
- result.new_local_correct.value().signon_realm = correct_signon_realm;
- }
-
- // Set the incorrect local entry if needed.
- if (!local_incorrect_ps ||
- (newest_data != &local_incorrect_ps.value() &&
- !AreNonSyncTagFieldsEqual(local_incorrect_ps.value(), *newest_data))) {
- result.new_local_incorrect = PasswordFromSpecifics(*newest_data);
- result.new_local_incorrect.value().origin = GURL(incorrect_origin);
- result.new_local_incorrect.value().signon_realm = incorrect_signon_realm;
- }
- return result;
-}
-
} // namespace
struct PasswordSyncableService::SyncEntries {
@@ -336,9 +124,8 @@ struct PasswordSyncableService::SyncEntries {
PasswordSyncableService::PasswordSyncableService(
PasswordStoreSync* password_store)
- : password_store_(password_store),
- clock_(new base::DefaultClock),
- is_processing_sync_changes_(false) {}
+ : password_store_(password_store), is_processing_sync_changes_(false) {
+}
PasswordSyncableService::~PasswordSyncableService() = default;
@@ -374,12 +161,17 @@ syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
}
merge_result.set_num_items_before_association(new_local_entries.size());
- // Changes from Sync to be applied locally.
SyncEntries sync_entries;
// Changes from password db that need to be propagated to sync.
syncer::SyncChangeList updated_db_entries;
- MergeSyncDataWithLocalData(initial_sync_data, &new_local_entries,
- &sync_entries, &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,
+ &sync_entries,
+ &updated_db_entries);
+ }
for (PasswordEntryMap::iterator it = new_local_entries.begin();
it != new_local_entries.end(); ++it) {
@@ -443,7 +235,7 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::AutoReset<bool> processing_changes(&is_processing_sync_changes_, true);
SyncEntries sync_entries;
- base::Time time_now = clock_->Now();
+ base::Time time_now = base::Time::Now();
for (syncer::SyncChangeList::const_iterator it = change_list.begin();
it != change_list.end(); ++it) {
@@ -456,13 +248,6 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
}
AppendPasswordFromSpecifics(
specifics.password().client_only_encrypted_data(), time_now, entries);
- if (IsValidAndroidFacetURI(entries->back()->signon_realm)) {
- // Fix the Android Autofill credentials if needed.
- entries->back()->signon_realm =
- GetCorrectAndroidSignonRealm(entries->back()->signon_realm);
- entries->back()->origin =
- GURL(GetCorrectAndroidSignonRealm(entries->back()->origin.spec()));
- }
}
WriteToPasswordStore(sync_entries);
@@ -553,132 +338,21 @@ void PasswordSyncableService::WriteToPasswordStore(const SyncEntries& entries) {
password_store_->NotifyLoginsChanged(changes);
}
-void PasswordSyncableService::MergeSyncDataWithLocalData(
- const syncer::SyncDataList& sync_data,
- PasswordEntryMap* unmatched_data_from_password_db,
- SyncEntries* sync_entries,
- syncer::SyncChangeList* updated_db_entries) {
- std::map<std::string, const sync_pb::PasswordSpecificsData*> sync_data_map;
- for (const auto& data : sync_data) {
- const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
- const sync_pb::PasswordSpecificsData* password_specifics =
- &specifics.password().client_only_encrypted_data();
- sync_data_map[MakePasswordSyncTag(*password_specifics)] =
- password_specifics;
- }
- DCHECK_EQ(sync_data_map.size(), sync_data.size());
-
- for (auto it = sync_data_map.begin(); it != sync_data_map.end();) {
- if (IsValidAndroidFacetURI(it->second->signon_realm())) {
- // Perform deduplication of Android credentials saved in the wrong format.
- // For each incorrect entry, a duplicate of it is created in the correct
- // format, so Chrome can make use of it. The incorrect sync entries are
- // not deleted for now.
- std::string incorrect_tag = AndroidAutofillSyncTag(*it->second);
- std::string correct_tag = AndroidCorrectSyncTag(*it->second);
- auto it_sync_incorrect = sync_data_map.find(incorrect_tag);
- auto it_sync_correct = sync_data_map.find(correct_tag);
- auto it_local_data_correct =
- unmatched_data_from_password_db->find(correct_tag);
- auto it_local_data_incorrect =
- unmatched_data_from_password_db->find(incorrect_tag);
- if ((it != it_sync_incorrect && it != it_sync_correct) ||
- (it_sync_incorrect == sync_data_map.end() &&
- it_local_data_incorrect == unmatched_data_from_password_db->end())) {
- // The current credential is in an unexpected format or incorrect
- // credential don't exist. Just do what Sync would normally do.
- CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db,
- sync_entries, updated_db_entries);
- ++it;
- } else {
- AndroidMergeResult result = Perform4WayMergeAndroidCredentials(
- it_sync_correct == sync_data_map.end() ? nullptr
- : it_sync_correct->second,
- it_sync_incorrect == sync_data_map.end()
- ? nullptr
- : it_sync_incorrect->second,
- it_local_data_correct == unmatched_data_from_password_db->end()
- ? nullptr
- : it_local_data_correct->second,
- it_local_data_incorrect == unmatched_data_from_password_db->end()
- ? nullptr
- : it_local_data_incorrect->second);
- // Add or update the correct local entry.
- if (result.new_local_correct) {
- auto* local_changes = sync_entries->EntriesForChangeType(
- it_local_data_correct == unmatched_data_from_password_db->end()
- ? syncer::SyncChange::ACTION_ADD
- : syncer::SyncChange::ACTION_UPDATE);
- local_changes->push_back(std::make_unique<autofill::PasswordForm>(
- result.new_local_correct.value()));
- local_changes->back()->date_synced = clock_->Now();
- }
- // Add or update the incorrect local entry.
- if (result.new_local_incorrect) {
- auto* local_changes = sync_entries->EntriesForChangeType(
- it_local_data_incorrect == unmatched_data_from_password_db->end()
- ? syncer::SyncChange::ACTION_ADD
- : syncer::SyncChange::ACTION_UPDATE);
- local_changes->push_back(std::make_unique<autofill::PasswordForm>(
- result.new_local_incorrect.value()));
- local_changes->back()->date_synced = clock_->Now();
- }
- if (it_local_data_correct != unmatched_data_from_password_db->end())
- unmatched_data_from_password_db->erase(it_local_data_correct);
- if (it_local_data_incorrect != unmatched_data_from_password_db->end())
- unmatched_data_from_password_db->erase(it_local_data_incorrect);
- // Add or update the correct sync entry.
- if (result.new_android_correct) {
- updated_db_entries->push_back(
- syncer::SyncChange(FROM_HERE,
- it_sync_correct == sync_data_map.end()
- ? syncer::SyncChange::ACTION_ADD
- : syncer::SyncChange::ACTION_UPDATE,
- result.new_android_correct.value()));
- }
- // Add or update the Android Autofill sync entry.
- if (result.new_android_incorrect) {
- updated_db_entries->push_back(
- syncer::SyncChange(FROM_HERE,
- it_sync_incorrect == sync_data_map.end()
- ? syncer::SyncChange::ACTION_ADD
- : syncer::SyncChange::ACTION_UPDATE,
- result.new_android_incorrect.value()));
- }
- bool increment = true;
- for (auto sync_data_it : {it_sync_incorrect, it_sync_correct}) {
- if (sync_data_it != sync_data_map.end()) {
- if (sync_data_it == it) {
- it = sync_data_map.erase(it);
- increment = false;
- } else {
- sync_data_map.erase(sync_data_it);
- }
- }
- }
- if (increment)
- ++it;
- }
- } else {
- // Not Android.
- CreateOrUpdateEntry(*it->second, unmatched_data_from_password_db,
- sync_entries, updated_db_entries);
- ++it;
- }
- }
-}
-
+// static
void PasswordSyncableService::CreateOrUpdateEntry(
- const sync_pb::PasswordSpecificsData& password_specifics,
+ const syncer::SyncData& data,
PasswordEntryMap* unmatched_data_from_password_db,
SyncEntries* 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 =
unmatched_data_from_password_db->find(tag);
- base::Time time_now = clock_->Now();
+ base::Time time_now = base::Time::Now();
if (existing_local_entry_iter == unmatched_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.
@@ -726,7 +400,31 @@ syncer::SyncData SyncDataFromPassword(
sync_pb::EntitySpecifics password_data;
sync_pb::PasswordSpecificsData* password_specifics =
password_data.mutable_password()->mutable_client_only_encrypted_data();
- PasswordSpecificsFromPassword(password_form, password_specifics);
+#define CopyField(field) password_specifics->set_##field(password_form.field)
+#define CopyStringField(field) \
+ password_specifics->set_##field(base::UTF16ToUTF8(password_form.field))
+ CopyField(scheme);
+ CopyField(signon_realm);
+ password_specifics->set_origin(password_form.origin.spec());
+ password_specifics->set_action(password_form.action.spec());
+ CopyStringField(username_element);
+ CopyStringField(password_element);
+ CopyStringField(username_value);
+ CopyStringField(password_value);
+ CopyField(preferred);
+ password_specifics->set_date_created(
+ password_form.date_created.ToInternalValue());
+ password_specifics->set_blacklisted(password_form.blacklisted_by_user);
+ CopyField(type);
+ CopyField(times_used);
+ CopyStringField(display_name);
+ password_specifics->set_avatar_url(password_form.icon_url.spec());
+ password_specifics->set_federation_url(
+ password_form.federation_origin.unique()
+ ? std::string()
+ : password_form.federation_origin.Serialize());
+#undef CopyStringField
+#undef CopyField
std::string tag = MakePasswordSyncTag(*password_specifics);
return syncer::SyncData::CreateLocalData(tag, tag, password_data);
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service.h b/chromium/components/password_manager/core/browser/password_syncable_service.h
index e2fd572c4fb..d86daac1974 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service.h
+++ b/chromium/components/password_manager/core/browser/password_syncable_service.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/sequence_checker.h"
-#include "base/time/clock.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_data.h"
@@ -61,12 +60,6 @@ class PasswordSyncableService : public syncer::SyncableService {
void InjectStartSyncFlare(
const syncer::SyncableService::StartSyncFlare& flare);
-#if defined(UNIT_TEST)
- void set_clock(std::unique_ptr<base::Clock> clock) {
- clock_ = std::move(clock);
- }
-#endif
-
private:
// Map from password sync tag to password form.
typedef std::map<std::string, autofill::PasswordForm*> PasswordEntryMap;
@@ -87,23 +80,14 @@ class PasswordSyncableService : public syncer::SyncableService {
// Uses the |PasswordStore| APIs to change entries.
void WriteToPasswordStore(const SyncEntries& entries);
- // Goes through |sync_data| and for each entry merges the data with
- // |unmatched_data_from_password_db|. The result of merge is recorded in
- // |sync_entries| or |updated_db_entries|. Successfully merged elements are
- // removed from |unmatched_data_from_password_db|.
- void MergeSyncDataWithLocalData(
- const syncer::SyncDataList& sync_data,
- PasswordEntryMap* unmatched_data_from_password_db,
- SyncEntries* sync_entries,
- syncer::SyncChangeList* updated_db_entries);
-
// Examines |data|, an entry in sync db, and updates |sync_entries| or
// |updated_db_entries| accordingly. An element is removed from
// |unmatched_data_from_password_db| if its tag is identical to |data|'s.
- void CreateOrUpdateEntry(const sync_pb::PasswordSpecificsData& data,
- PasswordEntryMap* unmatched_data_from_password_db,
- SyncEntries* sync_entries,
- syncer::SyncChangeList* updated_db_entries);
+ static void CreateOrUpdateEntry(
+ const syncer::SyncData& data,
+ PasswordEntryMap* unmatched_data_from_password_db,
+ SyncEntries* sync_entries,
+ syncer::SyncChangeList* updated_db_entries);
// Calls |operation| for each element in |entries| and appends the changes to
// |all_changes|.
@@ -125,9 +109,6 @@ class PasswordSyncableService : public syncer::SyncableService {
// A signal activated by this class to start sync as soon as possible.
syncer::SyncableService::StartSyncFlare flare_;
- // Clock for date_synced updates.
- std::unique_ptr<base::Clock> clock_;
-
// True if processing sync changes is in progress.
bool is_processing_sync_changes_;
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
index 9f1975d0895..39c4499a730 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
@@ -15,9 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
-#include "base/test/simple_test_clock.h"
#include "components/password_manager/core/browser/mock_password_store.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/model/sync_error_factory_mock.h"
@@ -54,8 +52,6 @@ namespace {
// PasswordForm values for tests.
constexpr autofill::PasswordForm::Type kArbitraryType =
autofill::PasswordForm::TYPE_GENERATED;
-constexpr char kAndroidAutofillRealm[] = "android://hash@com.magisto";
-constexpr char kAndroidCorrectRealm[] = "android://hash@com.magisto/";
constexpr char kIconUrl[] = "https://fb.com/Icon";
constexpr char kDisplayName[] = "Agent Smith";
constexpr char kFederationUrl[] = "https://fb.com/";
@@ -73,8 +69,8 @@ const sync_pb::PasswordSpecificsData& GetPasswordSpecifics(
return sync_data.GetSpecifics().password().client_only_encrypted_data();
}
-MATCHER_P(HasDateSynced, time, "") {
- return arg.date_synced == time;
+MATCHER(HasDateSynced, "") {
+ return !arg.date_synced.is_null() && !arg.date_synced.is_max();
}
MATCHER_P(PasswordIs, form, "") {
@@ -127,14 +123,6 @@ ACTION_P(AppendForm, form) {
return true;
}
-// The argument is std::vector<autofill::PasswordForm*>*. The caller is
-// responsible for the lifetime of all the password forms.
-ACTION_P(AppendForms, forms) {
- for (const autofill::PasswordForm& form : forms)
- arg0->push_back(std::make_unique<autofill::PasswordForm>(form));
- return true;
-}
-
// Creates a sync data consisting of password specifics. The sign on realm is
// set to |signon_realm|.
SyncData CreateSyncData(const std::string& signon_realm) {
@@ -185,14 +173,12 @@ class PasswordSyncableServiceWrapper {
password_store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
service_.reset(
new PasswordSyncableService(password_store_->GetSyncInterface()));
- auto clock = std::make_unique<base::SimpleTestClock>();
- clock->SetNow(time());
- service_->set_clock(std::move(clock));
- ON_CALL(*password_store_, AddLoginImpl(HasDateSynced(time())))
+
+ ON_CALL(*password_store_, AddLoginImpl(HasDateSynced()))
.WillByDefault(Return(PasswordStoreChangeList()));
ON_CALL(*password_store_, RemoveLoginImpl(_))
.WillByDefault(Return(PasswordStoreChangeList()));
- ON_CALL(*password_store_, UpdateLoginImpl(HasDateSynced(time())))
+ ON_CALL(*password_store_, UpdateLoginImpl(HasDateSynced()))
.WillByDefault(Return(PasswordStoreChangeList()));
EXPECT_CALL(*password_store(), NotifyLoginsChanged(_)).Times(AnyNumber());
}
@@ -203,8 +189,6 @@ class PasswordSyncableServiceWrapper {
PasswordSyncableService* service() { return service_.get(); }
- static base::Time time() { return base::Time::FromInternalValue(100000); }
-
// Returnes the scoped_ptr to |service_| thus NULLing out it.
std::unique_ptr<syncer::SyncChangeProcessor> ReleaseSyncableService() {
return std::move(service_);
@@ -233,6 +217,7 @@ class PasswordSyncableServiceTest : public testing::Test {
std::unique_ptr<MockSyncChangeProcessor> processor_;
private:
+ // Used by the password store.
base::test::ScopedTaskEnvironment scoped_task_environment_;
PasswordSyncableServiceWrapper wrapper_;
};
@@ -677,546 +662,6 @@ TEST_F(PasswordSyncableServiceTest, SerializeNonEmptyPasswordForm) {
EXPECT_EQ("https://google.com", specifics.federation_url());
}
-// Tests for Android Autofill credentials. Those are saved in the wrong format
-// without trailing '/'. Nevertheless, password store should always contain the
-// correct values.
-class PasswordSyncableServiceAndroidAutofillTest : public testing::Test {
- public:
- PasswordSyncableServiceAndroidAutofillTest() = default;
-
- static PasswordFormData android_incorrect(double creation_time) {
- PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML,
- kAndroidAutofillRealm,
- kAndroidAutofillRealm,
- "",
- L"",
- L"",
- L"",
- L"username_value_1",
- L"11111",
- true,
- creation_time};
- return data;
- }
-
- static PasswordFormData android_correct(double creation_time) {
- PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML,
- kAndroidCorrectRealm,
- kAndroidCorrectRealm,
- "",
- L"",
- L"",
- L"",
- L"username_value_1",
- L"22222",
- true,
- creation_time};
- return data;
- }
-
- static PasswordFormData android_incorrect2(double creation_time) {
- PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML,
- kAndroidAutofillRealm,
- kAndroidAutofillRealm,
- "",
- L"",
- L"",
- L"",
- L"username_value_1",
- L"33333",
- false,
- creation_time};
- return data;
- }
-
- static PasswordFormData android_correct2(double creation_time) {
- PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML,
- kAndroidCorrectRealm,
- kAndroidCorrectRealm,
- "",
- L"",
- L"",
- L"",
- L"username_value_1",
- L"444444",
- false,
- creation_time};
- return data;
- }
-
- static autofill::PasswordForm FormWithCorrectTag(PasswordFormData data) {
- autofill::PasswordForm form = *FillPasswordFormWithData(data);
- form.signon_realm = kAndroidCorrectRealm;
- form.origin = GURL(kAndroidCorrectRealm);
- form.date_synced = PasswordSyncableServiceWrapper::time();
- return form;
- }
-
- static autofill::PasswordForm FormWithAndroidAutofillTag(
- PasswordFormData data) {
- autofill::PasswordForm form = *FillPasswordFormWithData(data);
- form.signon_realm = kAndroidAutofillRealm;
- form.origin = GURL(kAndroidAutofillRealm);
- form.date_synced = PasswordSyncableServiceWrapper::time();
- return form;
- }
-
- // Transforms |val| into |count| numbers from 1 to |count| inclusive.
- static std::vector<unsigned> ExtractTimestamps(unsigned val, unsigned count) {
- std::vector<unsigned> result;
- for (unsigned i = 0; i < count; ++i) {
- result.push_back(val % count + 1);
- val /= count;
- }
- return result;
- }
-
- static testing::Message FormDataMessage(const std::string& prefix,
- const PasswordFormData* data) {
- testing::Message message;
- message << prefix;
- if (data)
- message << *FillPasswordFormWithData(*data);
- else
- message << "NULL";
- return message;
- }
-
- protected:
- base::test::ScopedTaskEnvironment scoped_task_environment_;
-};
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, FourWayMerge) {
- for (unsigned val = 0; val < 4 * 4 * 4 * 4; ++val) {
- // Generate 4 creation timestamps for all the entries.
- std::vector<unsigned> dates = ExtractTimestamps(val, 4);
- ASSERT_EQ(4u, dates.size());
- const unsigned latest = *std::max_element(dates.begin(), dates.end());
- // Sync correct, Sync Android autofill, local correct, local incorrect.
- const PasswordFormData data[4] = {
- android_correct(dates[0]), android_incorrect(dates[1]),
- android_correct2(dates[2]), android_incorrect2(dates[3])};
- const PasswordFormData* latest_data =
- std::find_if(data, data + 4, [latest](const PasswordFormData& data) {
- return data.creation_time == latest;
- });
- ASSERT_TRUE(latest_data);
- std::vector<autofill::PasswordForm> expected_sync_updates;
- if (latest_data != &data[0])
- expected_sync_updates.push_back(FormWithCorrectTag(*latest_data));
- if (latest_data != &data[1])
- expected_sync_updates.push_back(FormWithAndroidAutofillTag(*latest_data));
- autofill::PasswordForm local_correct = *FillPasswordFormWithData(data[2]);
- autofill::PasswordForm local_incorrect = *FillPasswordFormWithData(data[3]);
- syncer::SyncData sync_correct =
- SyncDataFromPassword(*FillPasswordFormWithData(data[0]));
- syncer::SyncData sync_incorrect =
- SyncDataFromPassword(*FillPasswordFormWithData(data[1]));
-
- SCOPED_TRACE(*FillPasswordFormWithData(data[0]));
- SCOPED_TRACE(*FillPasswordFormWithData(data[1]));
- SCOPED_TRACE(*FillPasswordFormWithData(data[2]));
- SCOPED_TRACE(*FillPasswordFormWithData(data[3]));
-
- for (bool correct_sync_first : {true, false}) {
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- std::vector<autofill::PasswordForm> stored_forms = {local_correct,
- local_incorrect};
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForms(stored_forms));
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- if (latest_data != &data[2]) {
- EXPECT_CALL(*wrapper->password_store(),
- UpdateLoginImpl(FormWithCorrectTag(*latest_data)));
- }
- if (latest_data != &data[3]) {
- EXPECT_CALL(*wrapper->password_store(),
- UpdateLoginImpl(FormWithAndroidAutofillTag(*latest_data)));
- }
-
- if (expected_sync_updates.size() == 1) {
- EXPECT_CALL(*processor,
- ProcessSyncChanges(_, ElementsAre(SyncChangeIs(
- SyncChange::ACTION_UPDATE,
- expected_sync_updates[0]))));
- } else {
- EXPECT_CALL(
- *processor,
- ProcessSyncChanges(_, UnorderedElementsAre(
- SyncChangeIs(SyncChange::ACTION_UPDATE,
- expected_sync_updates[0]),
- SyncChangeIs(SyncChange::ACTION_UPDATE,
- expected_sync_updates[1]))));
- }
-
- SyncDataList sync_list = {sync_correct, sync_incorrect};
- if (!correct_sync_first)
- std::swap(sync_list[0], sync_list[1]);
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, sync_list, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations on
- // it are checked.
- scoped_task_environment_.RunUntilIdle();
- }
- }
-}
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, ThreeWayMerge) {
- for (int j = 0; j < 4; ++j) {
- // Whether the entry exists: Sync correct, Sync Android autofill,
- // local correct, local incorrect.
- bool entry_present[4] = {true, true, true, true};
- entry_present[j] = false;
- for (unsigned val = 0; val < 3 * 3 * 3; ++val) {
- // Generate 3 creation timestamps for all the entries.
- std::vector<unsigned> dates = ExtractTimestamps(val, 3);
- ASSERT_EQ(3u, dates.size());
- const unsigned latest = *std::max_element(dates.begin(), dates.end());
-
- // Sync correct, Sync Android autofill, local correct, local incorrect.
- std::vector<std::unique_ptr<PasswordFormData>> data;
- int date_index = 0;
- data.push_back(entry_present[0]
- ? std::make_unique<PasswordFormData>(
- android_correct(dates[date_index++]))
- : nullptr);
- data.push_back(entry_present[1]
- ? std::make_unique<PasswordFormData>(
- android_incorrect(dates[date_index++]))
- : nullptr);
- data.push_back(entry_present[2]
- ? std::make_unique<PasswordFormData>(
- android_correct2(dates[date_index++]))
- : nullptr);
- data.push_back(entry_present[3]
- ? std::make_unique<PasswordFormData>(
- android_incorrect2(dates[date_index++]))
- : nullptr);
-
- SCOPED_TRACE(val);
- SCOPED_TRACE(j);
- SCOPED_TRACE(FormDataMessage("data[0]=", data[0].get()));
- SCOPED_TRACE(FormDataMessage("data[1]=", data[1].get()));
- SCOPED_TRACE(FormDataMessage("data[2]=", data[2].get()));
- SCOPED_TRACE(FormDataMessage("data[3]=", data[3].get()));
-
- const PasswordFormData* latest_data =
- std::find_if(data.begin(), data.end(),
- [latest](const std::unique_ptr<PasswordFormData>& data) {
- return data && data->creation_time == latest;
- })
- ->get();
- ASSERT_TRUE(latest_data);
- std::vector<std::pair<SyncChange::SyncChangeType, autofill::PasswordForm>>
- expected_sync_updates;
- for (int i = 0; i < 2; ++i) {
- if (latest_data != data[i].get()) {
- expected_sync_updates.push_back(std::make_pair(
- data[i] ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
- i == 0 ? FormWithCorrectTag(*latest_data)
- : FormWithAndroidAutofillTag(*latest_data)));
- }
- }
-
- std::vector<autofill::PasswordForm> stored_forms;
- for (int i = 2; i < 4; ++i) {
- if (data[i])
- stored_forms.push_back(*FillPasswordFormWithData(*data[i]));
- }
-
- SyncDataList sync_list;
- for (int i = 0; i < 2; ++i) {
- if (data[i]) {
- sync_list.push_back(
- SyncDataFromPassword(*FillPasswordFormWithData(*data[i])));
- }
- }
-
- for (bool swap_sync_list : {false, true}) {
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForms(stored_forms));
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- for (int i = 2; i < 4; ++i) {
- if (latest_data != data[i].get()) {
- autofill::PasswordForm latest_form =
- i == 2 ? FormWithCorrectTag(*latest_data)
- : FormWithAndroidAutofillTag(*latest_data);
- if (data[i]) {
- EXPECT_CALL(*wrapper->password_store(),
- UpdateLoginImpl(latest_form));
- } else {
- EXPECT_CALL(*wrapper->password_store(),
- AddLoginImpl(latest_form));
- }
- }
- }
-
- if (expected_sync_updates.size() == 0) {
- EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty()));
- } else if (expected_sync_updates.size() == 1) {
- EXPECT_CALL(
- *processor,
- ProcessSyncChanges(_, ElementsAre(SyncChangeIs(
- expected_sync_updates[0].first,
- expected_sync_updates[0].second))));
- } else if (expected_sync_updates.size() == 2) {
- EXPECT_CALL(
- *processor,
- ProcessSyncChanges(
- _, UnorderedElementsAre(
- SyncChangeIs(expected_sync_updates[0].first,
- expected_sync_updates[0].second),
- SyncChangeIs(expected_sync_updates[1].first,
- expected_sync_updates[1].second))));
- }
-
- if (swap_sync_list && sync_list.size() == 2)
- std::swap(sync_list[0], sync_list[1]);
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, sync_list, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations
- // on it are checked.
- scoped_task_environment_.RunUntilIdle();
- }
- }
- }
-}
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, TwoWayServerAndLocalMerge) {
- for (unsigned i = 0; i < 2 * 2; ++i) {
- // Generate 4 different combinations for local/server entries.
- std::vector<unsigned> combination = ExtractTimestamps(i, 2);
- ASSERT_EQ(2u, combination.size());
- const bool sync_data_correct = !!combination[0];
- const bool local_data_correct = !!combination[1];
-
- for (unsigned val = 0; val < 2 * 2; ++val) {
- std::vector<unsigned> dates = ExtractTimestamps(val, 2);
- ASSERT_EQ(2u, dates.size());
-
- const PasswordFormData sync_data = sync_data_correct
- ? android_correct(dates[0])
- : android_incorrect(dates[0]);
- const PasswordFormData local_data = local_data_correct
- ? android_correct2(dates[1])
- : android_incorrect2(dates[1]);
-
- const PasswordFormData* latest_data =
- dates[1] > dates[0] ? &local_data : &sync_data;
-
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForm(*FillPasswordFormWithData(local_data)));
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- if (!local_data_correct || latest_data == &sync_data) {
- if (local_data_correct) {
- EXPECT_CALL(*wrapper->password_store(),
- UpdateLoginImpl(FormWithCorrectTag(*latest_data)));
- } else {
- EXPECT_CALL(*wrapper->password_store(),
- AddLoginImpl(FormWithCorrectTag(*latest_data)));
- }
- }
- if (!local_data_correct && latest_data == &sync_data) {
- EXPECT_CALL(*wrapper->password_store(),
- UpdateLoginImpl(FormWithAndroidAutofillTag(*latest_data)));
- } else if (local_data_correct && !sync_data_correct) {
- EXPECT_CALL(*wrapper->password_store(),
- AddLoginImpl(FormWithAndroidAutofillTag(*latest_data)));
- }
-
- std::vector<std::pair<SyncChange::SyncChangeType, autofill::PasswordForm>>
- expected_sync_updates;
- // Deal with the correct sync entry and incorrect one.
- if (sync_data_correct) {
- if (latest_data != &sync_data) {
- expected_sync_updates.push_back(std::make_pair(
- SyncChange::ACTION_UPDATE, FormWithCorrectTag(*latest_data)));
- }
- if (!local_data_correct) {
- expected_sync_updates.push_back(
- std::make_pair(SyncChange::ACTION_ADD,
- FormWithAndroidAutofillTag(*latest_data)));
- }
- } else {
- expected_sync_updates.push_back(std::make_pair(
- SyncChange::ACTION_ADD, FormWithCorrectTag(*latest_data)));
- if (latest_data != &sync_data) {
- expected_sync_updates.push_back(
- std::make_pair(SyncChange::ACTION_UPDATE,
- FormWithAndroidAutofillTag(*latest_data)));
- }
- }
-
- // Set expectation on |processor|.
- if (expected_sync_updates.size() == 0) {
- EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty()));
- } else if (expected_sync_updates.size() == 1) {
- EXPECT_CALL(
- *processor,
- ProcessSyncChanges(
- _, ElementsAre(SyncChangeIs(expected_sync_updates[0].first,
- expected_sync_updates[0].second))));
- } else if (expected_sync_updates.size() == 2) {
- EXPECT_CALL(*processor,
- ProcessSyncChanges(
- _, UnorderedElementsAre(
- SyncChangeIs(expected_sync_updates[0].first,
- expected_sync_updates[0].second),
- SyncChangeIs(expected_sync_updates[1].first,
- expected_sync_updates[1].second))));
- }
-
- SyncDataList sync_list = {
- SyncDataFromPassword(*FillPasswordFormWithData(sync_data))};
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, sync_list, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations on
- // it are checked.
- scoped_task_environment_.RunUntilIdle();
- }
- }
-}
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, OneEntryOnly) {
- for (int i = 0; i < 3; ++i) {
- // The case when only local incorrect entry exists is excluded. It's very
- // exotic because a local incorrect entry can come only from the server.
- // In such a case a copy will be uploaded to the server and next
- // MergeDataAndStartSyncing will do a proper migration.
- SCOPED_TRACE(i);
- // Whether the entry exists: Sync correct, Sync Android autofill,
- // local correct, local incorrect.
- const bool entry_is_correct = i == 0 || i == 2;
- const bool entry_is_local = i >= 2;
- PasswordFormData data =
- entry_is_correct ? android_correct(100) : android_incorrect(100);
-
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- if (entry_is_local) {
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForm(*FillPasswordFormWithData(data)));
- } else {
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(Return(true));
- }
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- if (!entry_is_local && !entry_is_correct) {
- EXPECT_CALL(*wrapper->password_store(),
- AddLoginImpl(FormWithAndroidAutofillTag(data)));
- }
- if (!entry_is_local) {
- EXPECT_CALL(*wrapper->password_store(),
- AddLoginImpl(FormWithCorrectTag(data)));
- }
-
- if (entry_is_correct && !entry_is_local) {
- EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty()));
- } else {
- EXPECT_CALL(*processor,
- ProcessSyncChanges(
- _, ElementsAre(SyncChangeIs(SyncChange::ACTION_ADD,
- FormWithCorrectTag(data)))));
- }
-
- SyncDataList sync_list;
- if (!entry_is_local) {
- sync_list.push_back(
- SyncDataFromPassword(*FillPasswordFormWithData(data)));
- }
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, sync_list, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations on
- // it are checked.
- scoped_task_environment_.RunUntilIdle();
- }
-}
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, FourEqualEntries) {
- // Sync correct, Sync Android autofill, local correct, local incorrect with
- // the same content. Nothing should happen.
- const PasswordFormData data = android_correct(100);
- autofill::PasswordForm local_correct = FormWithCorrectTag(data);
- autofill::PasswordForm local_incorrect = FormWithAndroidAutofillTag(data);
- syncer::SyncData sync_correct = SyncDataFromPassword(local_correct);
- syncer::SyncData sync_incorrect = SyncDataFromPassword(local_incorrect);
-
- for (bool correct_sync_first : {true, false}) {
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- std::vector<autofill::PasswordForm> stored_forms = {local_correct,
- local_incorrect};
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForms(stored_forms));
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty()));
-
- SyncDataList sync_list = {sync_correct, sync_incorrect};
- if (!correct_sync_first)
- std::swap(sync_list[0], sync_list[1]);
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, sync_list, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations on
- // it are checked.
- scoped_task_environment_.RunUntilIdle();
- }
-}
-
-TEST_F(PasswordSyncableServiceAndroidAutofillTest, AndroidCorrectEqualEntries) {
- // Sync correct, local correct with the same content. Nothing should happen.
- const PasswordFormData data = android_correct(100);
- autofill::PasswordForm local_correct = FormWithCorrectTag(data);
- syncer::SyncData sync_correct = SyncDataFromPassword(local_correct);
-
- auto wrapper = std::make_unique<PasswordSyncableServiceWrapper>();
- auto processor =
- std::make_unique<testing::StrictMock<MockSyncChangeProcessor>>();
-
- EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForm(local_correct));
- EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
- .WillOnce(Return(true));
- EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty()));
-
- wrapper->service()->MergeDataAndStartSyncing(
- syncer::PASSWORDS, {sync_correct}, std::move(processor),
- std::unique_ptr<syncer::SyncErrorFactory>());
- wrapper.reset();
- // Wait til PasswordStore is destroy end therefore all the expectations on
- // it are checked.
- scoped_task_environment_.RunUntilIdle();
-}
-
} // namespace
} // namespace password_manager