chromium/components/autofill/core/browser/webdata/payments/autofill_wallet_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_sync_bridge.h"

#include <stddef.h>

#include <memory>
#include <string_view>
#include <utility>

#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/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/bank_account.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_benefit.h"
#include "components/autofill/core/browser/data_model/credit_card_benefit_test_api.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
#include "components/autofill/core/browser/data_model/payments_metadata.h"
#include "components/autofill/core/browser/payments/payments_customer_data.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/autofill_webdata_backend.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/autofill/core/common/autofill_payments_features.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/in_memory_metadata_change_list.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/data_type_progress_marker.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/sync/test/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace autofill {
namespace {

AutofillProfileChange;
CreditCardChange;
ScopedTempDir;
IbanChangeKey;
AutofillWalletSpecifics;
DataTypeState;
EntityMetadata;
DataBatch;
DataType;
EntityChange;
EntityData;
HasInitialSyncDone;
KeyAndData;
MockDataTypeLocalChangeProcessor;
NiceMock;
Pointee;
Return;
SizeIs;
UnorderedElementsAre;

// Represents a Payments customer id.
const char kCustomerDataId[] =;
const char kCustomerDataId2[] =;

// Unique client tags for the server data.
const char kCard1ClientTag[] =;
const char kCustomerDataClientTag[] =;
const char kCloudTokenDataClientTag[] =;
const char kBankAccountClientTag[] =;

const base::Time kJune2017 =;

const char kDefaultCacheGuid[] =;

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

std::string WalletMaskedCreditCardSpecificsAsDebugString(
    const AutofillWalletSpecifics& specifics) {}

std::string WalletCreditCardCloudTokenDataSpecificsAsDebugString(
    const AutofillWalletSpecifics& specifics) {}

std::string WalletBankAccountDetailsAsDebugString(
    const sync_pb::BankAccountDetails& bank_account_details) {}

std::string WalletPaymentInstrumentSupportedRailAsDebugString(
    const sync_pb::PaymentInstrument payment_instrument) {}

std::string WalletPaymentInstrumentAsDebugString(
    const AutofillWalletSpecifics& specifics) {}

std::string WalletMaskedIbanSpecificsAsDebugString(
    const AutofillWalletSpecifics& specifics) {}

std::string AutofillWalletSpecificsAsDebugString(
    const AutofillWalletSpecifics& specifics) {}

MATCHER_P(EqualsSpecifics, expected, "") {}

MATCHER_P(RemoveChange, key, "") {}

MATCHER_P2(AddChange, key, data, "") {}

}  // namespace

class AutofillWalletSyncBridgeTestBase {};

class AutofillWalletSyncBridgeTest : public testing::Test,
                                     public AutofillWalletSyncBridgeTestBase {};

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

TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) {}

TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCreditCardCloudTokenData) {}

TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForBankAccount) {}

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

TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) {}

TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCreditCardCloudTokenData) {}

TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForBankAccount) {}

TEST_F(AutofillWalletSyncBridgeTest,
       GetAllDataForDebugging_ShouldReturnAllData) {}

// Tests that when multiple credit card cloud token data have the same masked
// card id, the data can be obtained correctly.
TEST_F(AutofillWalletSyncBridgeTest,
       GetAllDataForDebugging_MultipleCloudTokenDataForOneCard) {}

// Tests that when a new wallet card is sent by the server, the client only
// keeps the new data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NewWalletCard) {}

// Tests that in initial sync, no metrics are recorded for new cards.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_NewWalletCardNoMetricsInitialSync) {}

// Tests that in initial sync, no metadata are synced for new IBANs.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_NewWalletIbanNoMetadataInitialSync) {}

// Tests that when a new payments customer data is sent by the server, the
// client only keeps the new data.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_NewPaymentsCustomerData) {}

// Tests that when a new credit card cloud token data is sent by the server,
// the client only keeps the new data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NewCloudTokenData) {}

// Tests that when the server sends no cards, the client should delete all it's
// existing data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NoWalletCard) {}

// Tests that when the server sends no IBANs, the client should delete all it's
// existing data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NoWalletIban) {}

// Tests that when the server sends no cloud token data, the client should
// delete all it's existing cloud token data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NoCloudTokenData) {}

// Tests that when the server sends the same data as the client has, nothing
// changes on the client.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_SameWalletCardAndCustomerDataAndCloudTokenData) {}

// Tests that when there are multiple changes happening at the same time, the
// data from the server is what the client ends up with.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_AddRemoveAndPreserveWalletCard) {}

// Test that all field values for a card sent from the server are copied on the
// card on the client.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_SetsAllWalletCardData) {}

// Test that all field values for a cloud token data sent from the server are
// copied on the client.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_SetsAllCloudTokenData) {}

// Tests that all field values for an IBAN sent from the server are copied on
// the client.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_SetsNewMaskedIban) {}

// Tests that when there are existing IBANs, the data from the server is what
// the client ends up with.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_UpdateAndRemoveMaskedIban) {}

// Test to verify the deletion of the server cvc for the card with the `REMOVE`
// change tag.
TEST_F(AutofillWalletSyncBridgeTest, DeletesServerCvcWhenCardIsDeleted) {}

TEST_F(AutofillWalletSyncBridgeTest, LoadMetadataCalled) {}

TEST_F(AutofillWalletSyncBridgeTest, ApplyDisableSyncChanges_Cards) {}

TEST_F(AutofillWalletSyncBridgeTest, ApplyDisableSyncChanges_Ibans) {}

// This test ensures that an int64 -> int conversion bug we encountered is
// fixed.
TEST_F(AutofillWalletSyncBridgeTest,
       LargeInstrumentIdProvided_CorrectDataStored) {}

// Test that it logs correctly when new cards with virtual card metadata are
// synced.
TEST_F(AutofillWalletSyncBridgeTest, SetWalletCards_LogVirtualMetadataSynced) {}

// Tests that all field values for `CreditCardBenefits` sent from the server
// are copied to the client when the `product_terms_url` is not empty.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_SetsNewCardBenefitWithTerms) {}

// Tests that all benefit related field values are deleted from client when the
// card from server has no `product_terms_url`.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_SetsNewCardBenefitWithoutTerms) {}

// Tests that when a new card benefit is sent by the server, the client only
// keeps the new data.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NewCardBenefit) {}

// Tests that the client should delete all its existing benefits when the
// server sends no benefits.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NoCardBenefit) {}

// Tests that when the server sends the same data as the client has, nothing
// changes on the client.
TEST_F(AutofillWalletSyncBridgeTest,
       MergeFullSyncData_SameWalletCardAndCardBenefit) {}

// Test suite for sync bridge with the benefit syncing feature disabled.
class AutofillWalletSyncBridgeTestWithBenefitSyncDisabled
    : public testing::Test,
      public AutofillWalletSyncBridgeTestBase {};

// Tests that benefit related data will not be saved on client when the benefit
// syncing feature is disabled.
TEST_F(AutofillWalletSyncBridgeTestWithBenefitSyncDisabled,
       MergeFullSyncData_SetsNewCardBenefitWithTerms) {}

// Tests that when a new card benefit is sent by the server, the client will
// delete all benefit related data if the benefit syncing feature is disabled.
TEST_F(AutofillWalletSyncBridgeTestWithBenefitSyncDisabled,
       MergeFullSyncData_NewCardBenefit) {}

// Tests that the client should delete all benefit related data when
// the benefit syncing feature is disabled.
TEST_F(AutofillWalletSyncBridgeTestWithBenefitSyncDisabled,
       MergeFullSyncData_NoCardBenefit) {}

// Tests that when the server sends the same data as the client has, benefit
// related data should be deleted from client when the benefit syncing feature
// is disabled.
TEST_F(AutofillWalletSyncBridgeTestWithBenefitSyncDisabled,
       MergeFullSyncData_SameWalletCardAndCardBenefit) {}

#if BUILDFLAG(IS_ANDROID)
TEST_F(AutofillWalletSyncBridgeTest, ApplyDisableSyncChanges_BankAccount) {
  base::test::ScopedFeatureList scoped_feature_list(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create one bank account on the client.
  table()->SetMaskedBankAccounts(
      {test::CreatePixBankAccount(/*instrument_id=*/1234)});

  EXPECT_CALL(*backend(), CommitChanges());
  EXPECT_CALL(*backend(),
              NotifyOnAutofillChangedBySync(syncer::AUTOFILL_WALLET_DATA));
  EXPECT_CALL(*backend(), NotifyOfIbanChanged).Times(0);

  // ApplyDisableSyncChanges indicates to the bridge that sync is stopping
  // because it was disabled.
  bridge()->ApplyDisableSyncChanges(
      std::make_unique<syncer::InMemoryMetadataChangeList>());

  EXPECT_TRUE(GetAllLocalData().empty());
}

// Tests that when the server sends the same data as the client has, nothing
// changes on the client.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_SameBankAccountData) {
  base::test::ScopedFeatureList scoped_feature_list(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create one bank account on the client.
  BankAccount existing_bank_account =
      test::CreatePixBankAccount(/*instrument_id=*/1234);
  EXPECT_TRUE(table()->SetMaskedBankAccounts({existing_bank_account}));
  std::vector<BankAccount> bank_accounts;
  table()->GetMaskedBankAccounts(bank_accounts);
  ASSERT_EQ(1U, bank_accounts.size());

  // Create the bank account on the server.
  AutofillWalletSpecifics bank_account_specifics;
  SetAutofillWalletSpecificsFromBankAccount(existing_bank_account,
                                            &bank_account_specifics);

  StartSyncing({bank_account_specifics});

  table()->GetMaskedBankAccounts(bank_accounts);
  EXPECT_EQ(1U, bank_accounts.size());
  EXPECT_THAT(GetAllLocalData(),
              UnorderedElementsAre(EqualsSpecifics(bank_account_specifics)));
}

// Tests that when the server sends a new bank account, it gets added to the
// database.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NewBankAccount) {
  base::test::ScopedFeatureList scoped_feature_list(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create one bank account on the client.
  BankAccount existing_bank_account =
      test::CreatePixBankAccount(/*instrument_id=*/1234);
  EXPECT_TRUE(table()->SetMaskedBankAccounts({existing_bank_account}));
  std::vector<BankAccount> bank_accounts;
  table()->GetMaskedBankAccounts(bank_accounts);
  ASSERT_EQ(1U, bank_accounts.size());
  AutofillWalletSpecifics existing_bank_account_specifics;
  SetAutofillWalletSpecificsFromBankAccount(existing_bank_account,
                                            &existing_bank_account_specifics);

  // Create the bank account on the server.
  BankAccount new_bank_account =
      test::CreatePixBankAccount(/*instrument_id=*/9999);
  AutofillWalletSpecifics new_bank_account_specifics;
  SetAutofillWalletSpecificsFromBankAccount(new_bank_account,
                                            &new_bank_account_specifics);

  StartSyncing({new_bank_account_specifics, existing_bank_account_specifics});

  table()->GetMaskedBankAccounts(bank_accounts);
  EXPECT_EQ(2U, bank_accounts.size());
  EXPECT_THAT(
      GetAllLocalData(),
      UnorderedElementsAre(EqualsSpecifics(existing_bank_account_specifics),
                           EqualsSpecifics(new_bank_account_specifics)));
}

// Tests that when the server sends an updated bank account, it gets updated in
// the database.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_UpdatedBankAccount) {
  base::test::ScopedFeatureList scoped_feature_list(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create one bank account on the client.
  BankAccount existing_bank_account =
      test::CreatePixBankAccount(/*instrument_id=*/1234);
  EXPECT_TRUE(table()->SetMaskedBankAccounts({existing_bank_account}));
  std::vector<BankAccount> bank_accounts;
  table()->GetMaskedBankAccounts(bank_accounts);
  ASSERT_EQ(1U, bank_accounts.size());

  // Update the bank account on the server. Only the instrument id is the same
  // as the existing bank account.
  BankAccount udpated_bank_account(
      existing_bank_account.payment_instrument().instrument_id(),
      u"updated_nickname", GURL("http://www.example-updated.com"),
      u"updated_bank_name", u"account_number_suffix_updated",
      BankAccount::AccountType::kSavings);

  AutofillWalletSpecifics updated_bank_account_specifics;
  SetAutofillWalletSpecificsFromBankAccount(udpated_bank_account,
                                            &updated_bank_account_specifics);

  StartSyncing({updated_bank_account_specifics});

  table()->GetMaskedBankAccounts(bank_accounts);
  EXPECT_EQ(1U, bank_accounts.size());
  EXPECT_THAT(
      GetAllLocalData(),
      UnorderedElementsAre(EqualsSpecifics(updated_bank_account_specifics)));
}

// Tests that when the server deletes a bank account, it gets removed from the
// database.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_RemoveBankAccount) {
  base::test::ScopedFeatureList scoped_feature_list(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create one bank account on the client.
  BankAccount bank_account_1 =
      test::CreatePixBankAccount(/*instrument_id=*/1234);
  BankAccount bank_account_2 =
      test::CreatePixBankAccount(/*instrument_id=*/9999);
  EXPECT_TRUE(table()->SetMaskedBankAccounts({bank_account_1, bank_account_2}));
  std::vector<BankAccount> bank_accounts;
  table()->GetMaskedBankAccounts(bank_accounts);
  ASSERT_EQ(2U, bank_accounts.size());
  AutofillWalletSpecifics bank_account_1_specifics;
  SetAutofillWalletSpecificsFromBankAccount(bank_account_1,
                                            &bank_account_1_specifics);

  // Remove bank account 2 on the server.
  StartSyncing({bank_account_1_specifics});

  table()->GetMaskedBankAccounts(bank_accounts);
  EXPECT_EQ(1U, bank_accounts.size());
  EXPECT_THAT(GetAllLocalData(),
              UnorderedElementsAre(EqualsSpecifics(bank_account_1_specifics)));
}

// Tests that when the server sends a new bank account, it does not get added to
// the database if the experiment is off.
TEST_F(AutofillWalletSyncBridgeTest, MergeFullSyncData_NewBankAccount_ExpOff) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndDisableFeature(
      features::kAutofillEnableSyncingOfPixBankAccounts);
  // Create a bank account on the server.
  BankAccount bank_account = test::CreatePixBankAccount(/*instrument_id=*/1234);
  std::vector<BankAccount> bank_accounts;
  AutofillWalletSpecifics bank_account_specifics;
  SetAutofillWalletSpecificsFromBankAccount(bank_account,
                                            &bank_account_specifics);

  StartSyncing({bank_account_specifics});

  table()->GetMaskedBankAccounts(bank_accounts);
  EXPECT_EQ(0U, bank_accounts.size());
}
#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace autofill