Commit 57093a57 authored by Jan Krcal's avatar Jan Krcal Committed by Commit Bot

Revert "Reland "Fix flaky test ServerAddressConvertsToSameLocalAddress""

This reverts commit ba52e783.

Reason for revert: This caused flakiness in the TwoClientAutofillProfileSyncTest.ClientsAddSameProfile test.

Original change's description:
> Reland "Fix flaky test ServerAddressConvertsToSameLocalAddress"
> 
> This is a reland of commit b3873b4d.
> 
> The CL fixes a race condition in production code of autofill profile
> sync bridge by modifying merge logic of the datatype. Previously, the
> logic for dealing with duplicate entities was to always prefer the
> remote one and silently delete the local one. This could end up with
> two clients having a different entry each and the sync server having
> both duplicate entries. The new behavior, introduced in this CL is to
> keep the profile with greater GUID, lexicographically.
> 
> This change should also remove flakiness of one integration test (that
> uncovered the actual issue), so the CL reenables the test.
> 
> The original CL caused flakiness in another integration test since GUIDs
> in that test are randomly attributed. In this reland, we fix this by
> making the expectation on the number of sync deletions depend on which
> one of the test GUIDs is bigger.
> 
> Bug: 917498
> Change-Id: I13994ac5bef8fcae41d37350e08ee80ab90f0916
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2002571
> Auto-Submit: Jan Krcal <jkrcal@chromium.org>
> Commit-Queue: Jan Krcal <jkrcal@chromium.org>
> Commit-Queue: Maxim Kolosovskiy <kolos@chromium.org>
> Reviewed-by: Maxim Kolosovskiy <kolos@chromium.org>
> Reviewed-by: Mikel Astiz <mastiz@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#733636}

TBR=kolos@chromium.org,jkrcal@chromium.org,mastiz@chromium.org

Change-Id: Ifad46c8c079b24a07c044b9d6a5ffdc77a439617
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 917498
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2013281Reviewed-by: default avatarJan Krcal <jkrcal@chromium.org>
Commit-Queue: Jan Krcal <jkrcal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#733910}
parent 1d0a2056
...@@ -188,6 +188,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest, ...@@ -188,6 +188,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
LOCAL_DELETION, 0); LOCAL_DELETION, 0);
} }
// Flaky on all platform. See crbug.com/971666
IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest, IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
AddDuplicateProfiles_OneIsVerified) { AddDuplicateProfiles_OneIsVerified) {
ASSERT_TRUE(SetupClients()); ASSERT_TRUE(SetupClients());
...@@ -209,20 +210,13 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest, ...@@ -209,20 +210,13 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin()); EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin()); EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
// Among duplicate profiles, sync prefers the one with largest GUID. If histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
// |profile0| (committed first) has a smaller GUID, client 1 should upload its LOCAL_DELETION, 0);
// deletion to the server. Otherwise, no deletion should occur.
if (profile1.guid() > profile0.guid()) {
histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
LOCAL_DELETION, 1);
} else {
histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
LOCAL_DELETION, 0);
}
} }
IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest, IN_PROC_BROWSER_TEST_F(
AddDuplicateProfiles_OneAtStart_OtherComesLater) { TwoClientAutofillProfileSyncTest,
AddDuplicateProfiles_OneIsVerified_NonverifiedComesLater) {
ASSERT_TRUE(SetupClients()); ASSERT_TRUE(SetupClients());
base::HistogramTester histograms; base::HistogramTester histograms;
...@@ -231,23 +225,26 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest, ...@@ -231,23 +225,26 @@ IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
autofill::test::GetVerifiedProfile(); // I.e. Full + Verified. autofill::test::GetVerifiedProfile(); // I.e. Full + Verified.
std::string verified_origin = profile1.origin(); std::string verified_origin = profile1.origin();
AddProfile(0, profile0); // We start by having the verified profile.
AddProfile(1, profile1);
ASSERT_TRUE(SetupSync()); ASSERT_TRUE(SetupSync());
EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait()); EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size()); EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
// Add the same (but verified) profile on the other client, afterwards. // Add the same (but non-verified) profile on the other client, afterwards.
AddProfile(1, profile1); AddProfile(0, profile0);
EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait()); EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
// The latter addition is caught in deduplication logic in PDM to sync. As a // The profiles should de-duplicate via sync on both other client, the
// result, both clients end up with the non-verified profile. // verified one should win.
EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size()); EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size()); EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
EXPECT_NE(verified_origin, GetAllAutoFillProfiles(0)[0]->origin()); EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
EXPECT_NE(verified_origin, GetAllAutoFillProfiles(1)[0]->origin()); EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE", histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
LOCAL_DELETION, 0); LOCAL_DELETION, 0);
......
...@@ -465,7 +465,7 @@ IN_PROC_BROWSER_TEST_F( ...@@ -465,7 +465,7 @@ IN_PROC_BROWSER_TEST_F(
// Flaky. http://crbug.com/917498 // Flaky. http://crbug.com/917498
IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest, IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
ServerAddressConvertsToSameLocalAddress) { DISABLED_ServerAddressConvertsToSameLocalAddress) {
GetFakeServer()->SetWalletData( GetFakeServer()->SetWalletData(
{CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"), {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
CreateDefaultSyncPaymentsCustomerData()}); CreateDefaultSyncPaymentsCustomerData()});
......
per-file *sync_bridge*=jkrcal@chromium.org per-file *sync_bridge*=jkrcal@chromium.org
per-file *sync_bridge*=file://components/sync/OWNERS per-file *sync_bridge*=file://components/sync/OWNERS
per-file autofill_profile_sync_difference_tracker*=jkrcal@chromium.org per-file *syncable_service*=jkrcal@chromium.org
per-file autofill_profile_sync_difference_tracker*=file://components/sync/OWNERS per-file *syncable_service*=file://components/sync/OWNERS
per-file *type_controller*=jkrcal@chromium.org per-file *type_controller*=jkrcal@chromium.org
per-file *type_controller*=file://components/sync/OWNERS per-file *type_controller*=file://components/sync/OWNERS
...@@ -251,18 +251,13 @@ base::Optional<syncer::ModelError> AutofillProfileSyncBridge::FlushSyncTracker( ...@@ -251,18 +251,13 @@ base::Optional<syncer::ModelError> AutofillProfileSyncBridge::FlushSyncTracker(
base::Unretained(web_data_backend_)))); base::Unretained(web_data_backend_))));
std::vector<std::unique_ptr<AutofillProfile>> profiles_to_upload_to_sync; std::vector<std::unique_ptr<AutofillProfile>> profiles_to_upload_to_sync;
std::vector<std::string> profiles_to_delete_from_sync; RETURN_IF_ERROR(tracker->FlushToSync(&profiles_to_upload_to_sync));
RETURN_IF_ERROR(tracker->FlushToSync(&profiles_to_upload_to_sync,
&profiles_to_delete_from_sync));
for (const std::unique_ptr<AutofillProfile>& entry : for (const std::unique_ptr<AutofillProfile>& entry :
profiles_to_upload_to_sync) { profiles_to_upload_to_sync) {
change_processor()->Put(GetStorageKeyFromAutofillProfile(*entry), change_processor()->Put(GetStorageKeyFromAutofillProfile(*entry),
CreateEntityDataFromAutofillProfile(*entry), CreateEntityDataFromAutofillProfile(*entry),
metadata_change_list.get()); metadata_change_list.get());
} }
for (const std::string& storage_key : profiles_to_delete_from_sync) {
change_processor()->Delete(storage_key, metadata_change_list.get());
}
return static_cast<syncer::SyncMetadataStoreChangeList*>( return static_cast<syncer::SyncMetadataStoreChangeList*>(
metadata_change_list.get()) metadata_change_list.get())
......
...@@ -64,11 +64,6 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile( ...@@ -64,11 +64,6 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
} }
// Check if profile appears under a different storage key to be de-duplicated. // Check if profile appears under a different storage key to be de-duplicated.
// TODO(crbug.com/1043683): Deal with rare cases when an remote update
// contains several exact duplicates (with different guids). We should not
// only search in local only entries but also in |update_to_local_| and
// |add_to_local_|. Likely needs a bit of refactoring to make the resulting
// code easy to understand.
for (const auto& pair : *GetLocalOnlyEntries()) { for (const auto& pair : *GetLocalOnlyEntries()) {
const std::string& local_storage_key = pair.first; const std::string& local_storage_key = pair.first;
const AutofillProfile& local = *pair.second; const AutofillProfile& local = *pair.second;
...@@ -76,76 +71,30 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile( ...@@ -76,76 +71,30 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
// Look for exact duplicates, compare only profile contents (and // Look for exact duplicates, compare only profile contents (and
// ignore origin and language code in comparison). // ignore origin and language code in comparison).
if (local.Compare(*remote) == 0) { if (local.Compare(*remote) == 0) {
// A duplicate found: keep the version with the bigger storage key. // We found a duplicate, we keep the new (remote) one and delete the
// local one.
DVLOG(2) DVLOG(2)
<< "[AUTOFILL SYNC] The profile " << "[AUTOFILL SYNC] The profile "
<< base::UTF16ToUTF8(local.GetRawInfo(NAME_FIRST)) << base::UTF16ToUTF8(local.GetRawInfo(NAME_FIRST))
<< base::UTF16ToUTF8(local.GetRawInfo(NAME_LAST)) << base::UTF16ToUTF8(local.GetRawInfo(NAME_LAST))
<< " already exists with a different storage key; keep the bigger " << " already exists with a different storage key; keep the remote key"
<< (remote_storage_key > local_storage_key ? "remote" : "local") << remote_storage_key << " and delete the local key "
<< " key " << std::max(remote_storage_key, local_storage_key) << local_storage_key;
<< " and delete the smaller key "
<< std::min(remote_storage_key, local_storage_key); // Ensure that a verified profile can never revert back to an unverified
if (remote_storage_key > local_storage_key) { // one. In such a case, take over the local origin for the new (remote)
// We keep the remote entity and delete the local one. // entry.
// Ensure that a verified profile can never revert back to an unverified if (local.IsVerified() && !remote->IsVerified()) {
// one. In such a case, take over the old origin for the new entry. remote->set_origin(local.origin());
if (local.IsVerified() && !remote->IsVerified()) { // Save a copy of the remote profile also to sync.
remote->set_origin(local.origin()); save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
// Save a copy of the remote profile also to sync.
save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
}
add_to_local_.push_back(std::move(remote));
// Deleting from sync is a no-op if it is local-only so far.
// There are a few ways how a synced local entry A could theoretically
// receive a remote duplicate B with a larger GUID:
// 1) Remote entity B got uploaded by another client through initial
// sync. That client thus also knew about A and issued a deletion of
// A at the same time. This client (if receiving creation of B
// first) resolves the conflict in the same way and re-issues the
// deletion of A. In most cases the redundant deletion does not even
// get sent as the processor already knows A got deleted remotely.
// 2) Remote entity B got uploaded by another client through race
// condition (i.e. not knowing about A, yet). In practice, this only
// happens when two clients simultaneously convert a server profile
// into local profiles. If the other client goes offline before
// receiving A, this client is responsible for deleting A from the
// server and thus must issue a deletion. (In most cases, the other
// client does not go offline and thus both clients issue a deletion
// of A independently).
// 3) (a paranoid case) Remote entity B got uploaded by another client
// by an error, i.e. already as a duplicate given their local state.
// Through standard flows, it should be impossible (duplicates are
// cought early in PDM code so such a change attempt does not even
// propagate to the sync bridge). Still, it's good to treat this
// case here for robustness.
delete_from_sync_.insert(local_storage_key);
DeleteFromLocal(local_storage_key);
} else {
// We keep the local entity and delete the remote one.
// Ensure that a verified profile can never revert back to an unverified
// one. In such a case, modify the origin and re-upload. Otherwise,
// there's no need to upload it: either is was already uploaded before
// (if this is incremental sync) or we'll upload it with all the
// remaining data in GetLocalOnlyEntries (if this is an initial sync).
if (remote->IsVerified() && !local.IsVerified()) {
auto modified_local = std::make_unique<AutofillProfile>(local);
modified_local->set_origin(remote->origin());
update_to_local_.push_back(
std::make_unique<AutofillProfile>(*modified_local));
save_to_sync_.push_back(std::move(modified_local));
// The local entity is already marked for upload so it is not local
// only anymore (we do not want to upload it once again while flushing
// if this is initial sync).
GetLocalOnlyEntries()->erase(local_storage_key);
}
delete_from_sync_.insert(remote_storage_key);
} }
return base::nullopt; // Delete the local profile that gets replaced by |remote|.
DeleteFromLocal(local_storage_key);
break;
} }
} }
// If no duplicate was found, just add the remote profile.
add_to_local_.push_back(std::move(remote)); add_to_local_.push_back(std::move(remote));
return base::nullopt; return base::nullopt;
} }
...@@ -183,14 +132,10 @@ Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToLocal( ...@@ -183,14 +132,10 @@ Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToLocal(
} }
Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToSync( Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToSync(
std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync, std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
std::vector<std::string>* profiles_to_delete_from_sync) {
for (std::unique_ptr<AutofillProfile>& entry : save_to_sync_) { for (std::unique_ptr<AutofillProfile>& entry : save_to_sync_) {
profiles_to_upload_to_sync->push_back(std::move(entry)); profiles_to_upload_to_sync->push_back(std::move(entry));
} }
for (const std::string& entry : delete_from_sync_) {
profiles_to_delete_from_sync->push_back(std::move(entry));
}
return base::nullopt; return base::nullopt;
} }
...@@ -255,11 +200,9 @@ AutofillProfileInitialSyncDifferenceTracker::IncorporateRemoteDelete( ...@@ -255,11 +200,9 @@ AutofillProfileInitialSyncDifferenceTracker::IncorporateRemoteDelete(
} }
Optional<ModelError> AutofillProfileInitialSyncDifferenceTracker::FlushToSync( Optional<ModelError> AutofillProfileInitialSyncDifferenceTracker::FlushToSync(
std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync, std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
std::vector<std::string>* profiles_to_delete_from_sync) {
// First, flush standard updates to sync. // First, flush standard updates to sync.
AutofillProfileSyncDifferenceTracker::FlushToSync( AutofillProfileSyncDifferenceTracker::FlushToSync(profiles_to_upload_to_sync);
profiles_to_upload_to_sync, profiles_to_delete_from_sync);
// For initial sync, we additionally need to upload all local only entries. // For initial sync, we additionally need to upload all local only entries.
if (!GetLocalOnlyEntries()) { if (!GetLocalOnlyEntries()) {
......
...@@ -50,12 +50,11 @@ class AutofillProfileSyncDifferenceTracker { ...@@ -50,12 +50,11 @@ class AutofillProfileSyncDifferenceTracker {
base::OnceClosure autofill_changes_callback); base::OnceClosure autofill_changes_callback);
// Writes into |profiles_to_upload_to_sync| all autofill profiles to be sent // Writes into |profiles_to_upload_to_sync| all autofill profiles to be sent
// to the sync server, and into |profiles_to_delete_from_sync| the storage // to the sync server. After flushing, not further remote changes should get
// keys of all profiles to be deleted from the server. After flushing, no // incorporated.
// further remote changes should get incorporated.
virtual base::Optional<syncer::ModelError> FlushToSync( virtual base::Optional<syncer::ModelError> FlushToSync(
std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync, std::vector<std::unique_ptr<AutofillProfile>>*
std::vector<std::string>* profiles_to_delete_from_sync); profiles_to_upload_to_sync);
protected: protected:
// If the entry is found, |entry| will be return, otherwise base::nullopt is // If the entry is found, |entry| will be return, otherwise base::nullopt is
...@@ -90,7 +89,7 @@ class AutofillProfileSyncDifferenceTracker { ...@@ -90,7 +89,7 @@ class AutofillProfileSyncDifferenceTracker {
// We use unique_ptrs for storing AutofillProfile to avoid unnecessary copies. // We use unique_ptrs for storing AutofillProfile to avoid unnecessary copies.
// Local data, mapped by storage key. Use GetLocalOnlyEntries() to access it. // Local data, mapped by storage key. Use unique_to_local() to access it.
std::map<std::string, std::unique_ptr<AutofillProfile>> local_only_entries_; std::map<std::string, std::unique_ptr<AutofillProfile>> local_only_entries_;
// Contain changes (originating from sync) that need to be saved to the local // Contain changes (originating from sync) that need to be saved to the local
...@@ -99,13 +98,9 @@ class AutofillProfileSyncDifferenceTracker { ...@@ -99,13 +98,9 @@ class AutofillProfileSyncDifferenceTracker {
std::vector<std::unique_ptr<AutofillProfile>> add_to_local_; std::vector<std::unique_ptr<AutofillProfile>> add_to_local_;
std::vector<std::unique_ptr<AutofillProfile>> update_to_local_; std::vector<std::unique_ptr<AutofillProfile>> update_to_local_;
// Contains data for entries that existed on both sync and local sides // Contains merged data for entries that existed on both sync and local sides
// and need to be saved back to sync. // and need to be saved back to sync.
std::vector<std::unique_ptr<AutofillProfile>> save_to_sync_; std::vector<std::unique_ptr<AutofillProfile>> save_to_sync_;
// Contains storage keys for entries that existed on both sync and local
// sides and need to be deleted from sync (because the conflict resolution
// preferred the local copies).
std::set<std::string> delete_from_sync_;
private: private:
DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTracker); DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTracker);
...@@ -121,8 +116,8 @@ class AutofillProfileInitialSyncDifferenceTracker ...@@ -121,8 +116,8 @@ class AutofillProfileInitialSyncDifferenceTracker
const std::string& storage_key) override; const std::string& storage_key) override;
base::Optional<syncer::ModelError> FlushToSync( base::Optional<syncer::ModelError> FlushToSync(
std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync, std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync)
std::vector<std::string>* profiles_to_delete_from_sync) override; override;
// Performs an additional pass through remote entries incorporated from sync // Performs an additional pass through remote entries incorporated from sync
// to find any similarities with local entries. Should be run after all // to find any similarities with local entries. Should be run after all
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment