chromium/components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge.h"

#include <stddef.h>

#include <algorithm>
#include <memory>
#include <sstream>
#include <utility>

#include "base/base64.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/test_autofill_clock.h"
#include "components/autofill/core/browser/webdata/autofill_sync_metadata_table.h"
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
#include "components/autofill/core/browser/webdata/payments/payments_sync_bridge_test_util.h"
#include "components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/os_crypt/sync/os_crypt_mocker.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/data_type.h"
#include "components/sync/engine/data_type_activation_response.h"
#include "components/sync/model/client_tag_based_data_type_processor.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/data_type_state.pb.h"
#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/test/mock_commit_queue.h"
#include "components/sync/test/mock_data_type_local_change_processor.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace autofill {
namespace {

ScopedTempDir;
IbanChangeKey;
WalletMetadataSpecifics;
DataBatch;
DataType;
EntityData;
KeyAndData;
MockDataTypeLocalChangeProcessor;
_;
ElementsAre;
ElementsAreArray;
IsEmpty;
Return;
UnorderedElementsAre;

// Non-UTF8 server IDs.
constexpr char kAddr1ServerId[] =;
constexpr char kAddr2ServerId[] =;
constexpr char kCard1ServerId[] =;
constexpr char kCard2ServerId[] =;

// Server IBAN instrument IDs.
constexpr Iban::InstrumentId kIban1InstrumentId =;
constexpr Iban::InstrumentId kIban2InstrumentId =;

// Base64 encodings of the server IDs, used as ids in WalletMetadataSpecifics
// (these are suitable for syncing, because they are valid UTF-8).
constexpr char kAddr1SpecificsId[] =;
constexpr char kCard1SpecificsId[] =;
constexpr char kCard2SpecificsId[] =;
constexpr char kIban1SpecificsId[] =;
constexpr char kIban2SpecificsId[] =;

const std::string kCard1StorageKey =;
const std::string kIban1StorageKey =;

// Unique sync tag for the server ID.
const char kCard1SyncTag[] =;
const char kIban1SyncTag[] =;

const char kLocalAddr1ServerId[] =;
const char kLocalAddr2ServerId[] =;

const char kDefaultCacheGuid[] =;

base::Time UseDateFromProtoValue(int64_t use_date_proto_value) {}

const base::Time kDefaultTime =;

int64_t UseDateToProtoValue(base::Time use_date) {}

std::string GetCardStorageKey(const std::string& specifics_id) {}

std::string GetIbanStorageKey(const std::string& specifics_id) {}

WalletMetadataSpecifics CreateWalletMetadataSpecificsForCardWithDetails(
    const std::string& specifics_id,
    size_t use_count,
    int64_t use_date,
    const std::string& billing_address_id = "") {}

WalletMetadataSpecifics CreateWalletMetadataSpecificsForCard(
    const std::string& specifics_id) {}

WalletMetadataSpecifics CreateWalletMetadataSpecificsForIbanWithDetails(
    const std::string& specifics_id,
    size_t use_count = 1,
    int64_t use_date = UseDateToProtoValue(kDefaultTime)) {}

CreditCard CreateServerCreditCardWithDetails(
    const std::string& server_id,
    size_t use_count,
    int64_t use_date,
    const std::string& billing_address_id = "") {}

Iban CreateServerIbanWithDetails(
    Iban::InstrumentId instrument_id,
    size_t use_count = 1,
    int64_t use_date = UseDateToProtoValue(kDefaultTime)) {}

CreditCard CreateLocalCreditCardWithDetails(size_t use_count,
                                            int64_t use_date) {}

CreditCard CreateServerCreditCardFromSpecifics(
    const WalletMetadataSpecifics& specifics) {}

Iban CreateServerIbanFromSpecifics(const WalletMetadataSpecifics& specifics) {}

void ExtractWalletMetadataSpecificsFromDataBatch(
    std::unique_ptr<DataBatch> batch,
    std::vector<WalletMetadataSpecifics>* output) {}

std::string WalletMetadataSpecificsAsDebugString(
    const WalletMetadataSpecifics& specifics) {}

std::vector<std::string> GetSortedSerializedSpecifics(
    const std::vector<WalletMetadataSpecifics>& specifics) {}

MATCHER_P(EqualsSpecifics, expected, "") {}

MATCHER_P(HasSpecifics, expected, "") {}

}  // namespace

class AutofillWalletMetadataSyncBridgeTest : public testing::Test {};

// The following two tests make sure client tags stay stable.
TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForCard) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForIban) {}

// The following two tests make sure storage keys stay stable.
TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForIban) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetAllDataForDebugging_ShouldReturnAllData_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetAllDataForDebugging_ShouldReturnAllData_Ibans) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetData_ShouldNotReturnNonexistentData) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetData_ShouldReturnSelectedData_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetData_ShouldReturnSelectedData_Ibans) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetData_ShouldReturnCompleteData_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       GetData_ShouldReturnCompleteData_Ibans) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       ApplyDisableSyncChanges_ShouldWipeLocalDataWhenSyncStopped_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       ApplyDisableSyncChanges_ShouldWipeLocalDataWhenSyncStopped_Ibans) {}

// Verify that lower values of metadata are not sent to the sync server when
// local metadata is updated.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DontSendLowerValueToServerOnUpdate_Cards) {}

// Verify that lower values of metadata are not sent to the sync server when
// local metadata is created (tests the case when metadata with higher use
// counts arrive before the data, the data bridge later notifies about creation
// for data that is already there).
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DontSendLowerValueToServerOnCreation_Cards) {}

// Verify that higher values of metadata are sent to the sync server when local
// metadata is updated.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendHigherValuesToServerOnLocalUpdate_Cards) {}

// Test that increase the value of `use_count` and `use_date` result in an
// update to the database.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendHigherValuesToServerOnLocalUpdate_Ibans) {}

// Verify that one-off addition of metadata is sent to the sync server.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendNewDataToServerOnLocalAddition_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendNewDataToServerOnLocalAddition_Ibans) {}

// Verify that one-off addition of metadata is sent to the sync server (even
// though it is notified as an update). This tests that the bridge is robust and
// recreates metadata that may get deleted in the mean-time).
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendNewDataToServerOnLocalUpdate_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       SendNewDataToServerOnLocalUpdate_Ibans) {}

// Verify that one-off deletion of existing metadata is sent to the sync server.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DeleteExistingDataFromServerOnLocalDeletion_Cards) {}

// Test that deleting the local IBAN will result in the deletion of existing
// IBAN data as well as IBAN metadata.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DeleteExistingAllDataFromServerOnLocalDeletion_Ibans) {}

// Verify that deletion of non-existing metadata is not sent to the sync server.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DoNotDeleteNonExistingDataFromServerOnLocalDeletion_Cards) {}

// Test that deleting the local IBAN will result in the deletion of existing
// IBAN data. It should be a no-op if there is no existing metadata.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DeleteExistingDataOnlyFromServerOnLocalDeletion_Ibans) {}

// Verify that updates of local (non-sync) credit cards are ignored.
// Regression test for crbug.com/1206306.
TEST_F(AutofillWalletMetadataSyncBridgeTest, DoNotPropagateNonSyncCards) {}

// Verify that old orphan metadata gets deleted on startup.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DeleteOldOrphanMetadataOnStartup_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DeleteOldOrphanMetadataOnStartup_Ibans) {}

// Verify that recent orphan metadata does not get deleted on startup.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DoNotDeleteOldNonOrphanMetadataOnStartup_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DoNotDeleteOldNonOrphanMetadataOnStartup_Ibans) {}

// Verify that recent orphan metadata does not get deleted on startup.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DoNotDeleteRecentOrphanMetadataOnStartup_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       DoNotDeleteRecentOrphanMetadataOnStartup_Ibans) {}

// Test that local cards that are not in the remote data set are uploaded during
// initial sync. This should rarely happen in practice because we wipe local
// data when disabling sync. Still there are corner cases such as when PDM
// manages to change metadata before the metadata bridge performs initial sync.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       InitialSync_UploadUniqueLocalData_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       InitialSync_UploadUniqueLocalData_Ibans) {}

// Test that the initial sync correctly distinguishes data that is unique in the
// local data set from data that is both in the local data and in the remote
// data. We should only upload the local data. This should rarely happen in
// practice because we wipe local data when disabling sync. Still there are
// corner cases such as when PDM manages to change metadata before the metadata
// bridge performs initial sync.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       InitialSync_UploadOnlyUniqueLocalData) {}

// Test that remote deletions are ignored.
TEST_F(AutofillWalletMetadataSyncBridgeTest,
       RemoteDeletion_ShouldNotDeleteExistingLocalData_Cards) {}

TEST_F(AutofillWalletMetadataSyncBridgeTest,
       RemoteDeletion_ShouldNotDeleteExistingLocalData_Ibans) {}

enum RemoteChangesMode {};

// Parametrized fixture for tests that apply in the same way for all
// RemoteChangesModes.
class AutofillWalletMetadataSyncBridgeRemoteChangesTest
    : public testing::WithParamInterface<RemoteChangesMode>,
      public AutofillWalletMetadataSyncBridgeTest {};

// No upstream communication or local DB change happens if the server sends an
// empty update.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EmptyUpdateIgnored) {}

// No upstream communication or local DB change happens if the server sends the
// same data as we have locally.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       SameDataIgnored_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       SameDataIgnored_Ibans) {}

// Tests that if the remote use stats are higher / newer, they should win over
// local stats.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_RemoteWins_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_RemoteWins_Ibans) {}

// Tests that if the local use stats are higher / newer, they should win over
// remote stats.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_LocalWins_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_LocalWins_Ibans) {}

// Tests that the conflicts are resolved component-wise (a higher use_count is
// taken from local data, a newer use_data is taken from remote data).
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_BothWin1_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_BothWin1_Ibans) {}

// Tests that the conflicts are resolved component-wise, like the previous test,
// only the other way around (a higher use_count is taken from remote data, a
// newer use_data is taken from local data).
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_BothWin2_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferHigherValues_BothWin2_Ibans) {}

// No merge logic is applied if local data has initial use_count (=1). In this
// situation, we just take over the remote entity completely.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferRemoteIfLocalHasInitialUseCount_Cards) {}

TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_PreferRemoteIfLocalHasInitialUseCount_Ibans) {}

// Tests that with a conflict in billing_address_id, we prefer an ID of a local
// profile over an ID of a server profile. In this test, the preferred ID is in
// the remote update that we need to store locally.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferLocalBillingAddressId_RemoteWins) {}

// Tests that with a conflict in billing_address_id, we prefer an ID of a local
// profile over an ID of a server profile. In this test, the preferred ID is in
// the local data that we need to upstream.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferLocalBillingAddressId_LocalWins) {}

// Tests that if both addresses have billing address ids of local profiles, we
// prefer the one from the most recently used entity. In this test, it is the
// remote entity.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfLocalIds_RemoteWins) {}

// Tests that if both addresses have billing address ids of local profiles, we
// prefer the one from the most recently used entity. In this test, it is the
// local entity.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfLocalIds_LocalWins) {}

// Tests that if both addresses have billing address ids of server profiles, we
// prefer the one from the most recently used entity. In this test, it is the
// remote entity.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfServerIds_RemoteWins) {}

// Tests that if both addresses have billing address ids of server profiles, we
// prefer the one from the most recently used entity. In this test, it is the
// local entity.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfServerIds_LocalWins) {}

// Tests that the conflict resolution happens component-wise. To avoid
// combinatorial explosion, this only tests when both have billing address ids
// of server profiles, one entity is more recently used but the other entity has
// a higher use_count. We should pick the billing_address_id of the newer one
// but have the use_count updated to the maximum as well. In this test, the
// remote entity is the more recently used.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfServerIds_BothWin1) {}

// Tests that the conflict resolution happens component-wise. To avoid
// combinatorial explosion, this only tests when both have billing address ids
// of server profiles, one entity is more recently used but the other entity has
// a higher use_count. We should pick the billing_address_id of the newer one
// but have the use_count updated to the maximum as well. In this test, the
// local entity is the more recently used.
TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest,
       Conflict_Card_PreferNewerBillingAddressOutOfServerIds_BothWin2) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace autofill

namespace sync_pb {

// Makes the GMock matchers print out a readable version of the protobuf.
void PrintTo(const WalletMetadataSpecifics& specifics, std::ostream* os) {}

}  // namespace sync_pb