Index: components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc |
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2c851f2fa47afe4a79e69659ccbf405883318ca1 |
--- /dev/null |
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc |
@@ -0,0 +1,454 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" |
+ |
+#include "base/strings/string_number_conversions.h" |
+#include "base/time/time.h" |
+#include "components/autofill/core/browser/autofill_profile.h" |
+#include "components/autofill/core/browser/credit_card.h" |
+#include "sync/api/sync_change.h" |
+#include "sync/api/sync_change_processor_wrapper_for_test.h" |
+#include "sync/api/sync_error_factory_mock.h" |
+#include "sync/protocol/autofill_specifics.pb.h" |
+#include "sync/protocol/sync.pb.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace autofill { |
+namespace { |
+ |
+using testing::DoAll; |
+using testing::NiceMock; |
+using testing::Return; |
+using testing::_; |
+ |
+ACTION_P(GetPointersTo, data_list) { |
+ for (auto& datum : *data_list) |
+ arg0->push_back(&datum); |
+} |
+ |
+// A syncable service for Wallet metadata that mocks out disk IO for server |
+// profiles and cards. |
+class MockAutofillWalletMetadataSyncableService |
+ : public AutofillWalletMetadataSyncableService { |
+ public: |
+ MockAutofillWalletMetadataSyncableService() |
+ : AutofillWalletMetadataSyncableService(nullptr, std::string()) { |
+ ON_CALL(*this, GetServerProfiles(_)) |
+ .WillByDefault(DoAll(GetPointersTo(&server_profiles_), Return(true))); |
+ |
+ ON_CALL(*this, GetServerCreditCards(_)) |
+ .WillByDefault(DoAll(GetPointersTo(&server_cards_), Return(true))); |
+ |
+ ON_CALL(*this, UpdateServerAddressUsageStats(_)) |
+ .WillByDefault(Return(true)); |
+ |
+ ON_CALL(*this, UpdateServerCardUsageStats(_)).WillByDefault(Return(true)); |
+ } |
+ |
+ ~MockAutofillWalletMetadataSyncableService() override {} |
+ |
+ MOCK_CONST_METHOD1(GetServerProfiles, bool(std::vector<AutofillProfile*>*)); |
+ MOCK_CONST_METHOD1(GetServerCreditCards, bool(std::vector<CreditCard*>*)); |
+ MOCK_METHOD1(UpdateServerAddressUsageStats, bool(const AutofillProfile&)); |
+ MOCK_METHOD1(UpdateServerCardUsageStats, bool(const CreditCard&)); |
+ |
+ // "Saves on disk" a server profile with the given |server_id|, |use_count|, |
+ // and |use_date|. |
+ void SaveServerProfile(const std::string& server_id, |
+ int64 use_count, |
+ int64 use_date) { |
+ AutofillProfile profile(AutofillProfile::SERVER_PROFILE, server_id); |
+ profile.set_use_count(use_count); |
+ profile.set_use_date(base::Time::FromInternalValue(use_date)); |
+ |
+ for (auto it = server_profiles_.begin(); it != server_profiles_.end(); |
+ ++it) { |
+ if (it->server_id() == server_id) { |
+ *it = profile; |
+ return; |
+ } |
+ } |
+ |
+ server_profiles_.push_back(profile); |
+ } |
+ |
+ // "Saves on disk" a server card with the given |server_id|, |use_count|, and |
+ // |use_date|. |
+ void SaveServerCard(const std::string& server_id, |
+ int64 use_count, |
+ int64 use_date) { |
+ CreditCard card(CreditCard::MASKED_SERVER_CARD, server_id); |
+ card.set_use_count(use_count); |
+ card.set_use_date(base::Time::FromInternalValue(use_date)); |
+ |
+ for (auto it = server_cards_.begin(); it != server_cards_.end(); ++it) { |
+ if (it->server_id() == server_id) { |
+ *it = card; |
+ return; |
+ } |
+ } |
+ |
+ server_cards_.push_back(card); |
+ } |
+ |
+ private: |
+ std::vector<AutofillProfile> server_profiles_; |
+ std::vector<CreditCard> server_cards_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockAutofillWalletMetadataSyncableService); |
+}; |
+ |
+// Verify that nothing is sent to the sync server when there's no metadata on |
+// disk. |
+TEST(AutofillWalletMetadataSyncableServiceTest, NoMetadataToReturn) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ EXPECT_TRUE(service.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA).empty()); |
+} |
+ |
+// Verify that all metadata from disk is sent to the sync server. |
+TEST(AutofillWalletMetadataSyncableServiceTest, ReturnAllMetadata) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ service.SaveServerProfile("data", 1, 2); |
+ service.SaveServerCard("data", 1, 2); |
+ |
+ syncer::SyncDataList data_list = |
+ service.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA); |
+ |
+ ASSERT_EQ(2UL, data_list.size()); |
+ EXPECT_NE(syncer::SyncDataLocal(data_list[0]).GetTag(), |
+ syncer::SyncDataLocal(data_list[1]).GetTag()); |
+ |
+ for (const syncer::SyncData& datum : data_list) { |
+ EXPECT_TRUE(datum.IsValid()); |
+ EXPECT_TRUE("address-data" == syncer::SyncDataLocal(datum).GetTag() || |
+ "card-data" == syncer::SyncDataLocal(datum).GetTag()); |
+ EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, datum.GetDataType()); |
+ EXPECT_EQ("data", datum.GetSpecifics().wallet_metadata().id()); |
+ EXPECT_EQ(1, datum.GetSpecifics().wallet_metadata().use_count()); |
+ EXPECT_EQ(2, datum.GetSpecifics().wallet_metadata().use_date()); |
+ } |
+} |
+ |
+// Verify that nothing is written to disk for empty sync changes. |
+TEST(AutofillWalletMetadataSyncableServiceTest, ProcessEmptyChanges) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ service.SaveServerProfile("addr", 1, 2); |
+ service.SaveServerCard("card", 3, 4); |
+ |
+ EXPECT_CALL(service, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(service, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ EXPECT_FALSE( |
+ service.ProcessSyncChanges(FROM_HERE, syncer::SyncChangeList()).IsSet()); |
+} |
+ |
+syncer::SyncChange BuildChange( |
+ syncer::SyncChange::SyncChangeType change_type, |
+ sync_pb::WalletMetadataSpecifics::Type metadata_type, |
+ const std::string& server_id, |
+ int64 use_count, |
+ int64 use_date) { |
+ sync_pb::EntitySpecifics entity; |
+ entity.mutable_wallet_metadata()->set_type(metadata_type); |
+ entity.mutable_wallet_metadata()->set_id(server_id); |
+ entity.mutable_wallet_metadata()->set_use_count(use_count); |
+ entity.mutable_wallet_metadata()->set_use_date(use_date); |
+ return syncer::SyncChange( |
+ FROM_HERE, change_type, |
+ syncer::SyncData::CreateLocalData(server_id, server_id, entity)); |
+} |
+ |
+MATCHER_P3(Matches, |
+ server_id, |
+ use_count, |
+ use_date, |
+ std::string(negation ? "isn't" : "is") + " server_id=" + server_id + |
+ " use_count=" + |
+ base::IntToString(use_count) + |
+ " use_date=" + |
+ base::IntToString(use_date)) { |
+ *result_listener << "where server_id=" << arg.server_id() |
+ << " use_count=" << arg.use_count() |
+ << " use_date=" << arg.use_date().ToInternalValue(); |
+ return arg.server_id() == server_id && |
+ arg.use_count() == static_cast<size_t>(use_count) && |
+ arg.use_date() == base::Time::FromInternalValue(use_date); |
+} |
+ |
+// Verify that sync changes are written to disk. |
+TEST(AutofillWalletMetadataSyncableServiceTest, ProcessChanges) { |
+ syncer::SyncChangeList changes; |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, |
+ sync_pb::WalletMetadataSpecifics::ADDRESS, |
+ "addr1", 1, 2)); |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, |
+ sync_pb::WalletMetadataSpecifics::ADDRESS, |
+ "addr2", 3, 4)); |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, |
+ sync_pb::WalletMetadataSpecifics::CARD, "card1", |
+ 5, 6)); |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, |
+ sync_pb::WalletMetadataSpecifics::CARD, "card2", |
+ 7, 8)); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ service.SaveServerProfile("addr1", 0, 0); |
+ service.SaveServerProfile("addr2", 0, 0); |
+ service.SaveServerCard("card1", 0, 0); |
+ service.SaveServerCard("card2", 0, 0); |
+ |
+ EXPECT_CALL(service, UpdateServerAddressUsageStats(Matches("addr1", 1, 2))); |
+ EXPECT_CALL(service, UpdateServerAddressUsageStats(Matches("addr2", 3, 4))); |
+ EXPECT_CALL(service, UpdateServerCardUsageStats(Matches("card1", 5, 6))); |
+ EXPECT_CALL(service, UpdateServerCardUsageStats(Matches("card2", 7, 8))); |
+ |
+ EXPECT_FALSE(service.ProcessSyncChanges(FROM_HERE, changes).IsSet()); |
+} |
+ |
+// Verify that local metadata is not changed if the sync server requests |
+// deletion. (Metadata life-cycle is tied to the corresponding Wallet data.) |
+TEST(AutofillWalletMetadataSyncableServiceTest, |
+ IgnoreSyncCommandsToDeleteMetadata) { |
+ syncer::SyncChangeList changes; |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_DELETE, |
+ sync_pb::WalletMetadataSpecifics::ADDRESS, |
+ "addr", 1, 2)); |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_DELETE, |
+ sync_pb::WalletMetadataSpecifics::CARD, "card", |
+ 3, 4)); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ service.SaveServerProfile("addr", 0, 0); |
+ service.SaveServerCard("card", 0, 0); |
+ |
+ EXPECT_CALL(service, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(service, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ EXPECT_FALSE(service.ProcessSyncChanges(FROM_HERE, changes).IsSet()); |
+} |
+ |
+// Verify that incoming sync messages do not write metadata for non-existent |
+// data. |
+TEST(AutofillWalletMetadataSyncableServiceTest, |
+ IgnoreOrphanMetadataInSyncChanges) { |
+ syncer::SyncChangeList changes; |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, |
+ sync_pb::WalletMetadataSpecifics::ADDRESS, |
+ "addr", 1, 2)); |
+ changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, |
+ sync_pb::WalletMetadataSpecifics::CARD, "card", |
+ 3, 4)); |
+ NiceMock<MockAutofillWalletMetadataSyncableService> service; |
+ |
+ EXPECT_CALL(service, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(service, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ EXPECT_FALSE(service.ProcessSyncChanges(FROM_HERE, changes).IsSet()); |
+} |
+ |
+void MergeMetadata(MockAutofillWalletMetadataSyncableService* local, |
+ MockAutofillWalletMetadataSyncableService* remote) { |
+ scoped_ptr<syncer::SyncErrorFactoryMock> errors( |
+ new syncer::SyncErrorFactoryMock); |
+ EXPECT_CALL(*errors, CreateAndUploadError(_, _)).Times(0); |
+ EXPECT_FALSE( |
+ local->MergeDataAndStartSyncing( |
+ syncer::AUTOFILL_WALLET_METADATA, |
+ remote->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA), |
+ scoped_ptr<syncer::SyncChangeProcessor>( |
+ new syncer::SyncChangeProcessorWrapperForTest(remote)), |
+ errors.Pass()) |
+ .error() |
+ .IsSet()); |
+} |
+ |
+// Verify that no writes happen when sync server sends no metadata. |
+TEST(AutofillWalletMetadataSyncableServiceTest, NoDataToMerge) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 1, 2); |
+ local.SaveServerCard("card", 3, 4); |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ |
+ EXPECT_CALL(local, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(local, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ MergeMetadata(&local, &remote); |
+} |
+ |
+// Verify that no writes happen when sync server sends metadata that is |
+// identical to the local metadata. |
+TEST(AutofillWalletMetadataSyncableServiceTest, IdenticalDataMerge) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 1, 2); |
+ local.SaveServerCard("card", 3, 4); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 1, 2); |
+ remote.SaveServerCard("card", 3, 4); |
+ |
+ EXPECT_CALL(local, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(local, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ MergeMetadata(&local, &remote); |
+} |
+ |
+// Verify that the larger use count and later use date overwrite the smaller use |
+// count and earlier use date when merging metadata. |
+TEST(AutofillWalletMetadataSyncableServiceTest, MergePicksMaxUseCountDate) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 50, 100); |
+ local.SaveServerCard("card", 100, 50); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 100, 50); |
+ remote.SaveServerCard("card", 50, 100); |
+ |
+ EXPECT_CALL(local, UpdateServerAddressUsageStats(Matches("addr", 100, 100))); |
+ EXPECT_CALL(local, UpdateServerCardUsageStats(Matches("card", 100, 100))); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(Matches("addr", 100, 100))); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(Matches("card", 100, 100))); |
+ |
+ MergeMetadata(&local, &remote); |
+} |
+ |
+// Verify that initial merge does not write metadata for non-existent data. |
+TEST(AutofillWalletMetadataSyncableServiceTest, |
+ IgnoreOrphanMetadataInInitialMerge) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 1, 2); |
+ remote.SaveServerCard("card", 3, 4); |
+ |
+ EXPECT_CALL(local, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(local, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ MergeMetadata(&local, &remote); |
+} |
+ |
+// Verify that updating Wallet data and metadata will send a message to the sync |
+// server. |
+TEST(AutofillWalletMetadataSyncableServiceTest, WalletDataUpdateSyncsMetadata) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 0, 0); |
+ local.SaveServerCard("card", 0, 0); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 0, 0); |
+ remote.SaveServerCard("card", 0, 0); |
+ |
+ MergeMetadata(&local, &remote); |
+ |
+ AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "addr"); |
+ profile.set_use_count(1); |
+ profile.set_use_date(base::Time::FromInternalValue(2)); |
+ |
+ CreditCard card(CreditCard::MASKED_SERVER_CARD, "card"); |
+ card.set_use_count(3); |
+ card.set_use_date(base::Time::FromInternalValue(4)); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(Matches("addr", 1, 2))); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(Matches("card", 3, 4))); |
+ |
+ local.AutofillProfileChanged(AutofillProfileChange( |
+ AutofillProfileChange::UPDATE, profile.guid(), &profile)); |
+ local.CreditCardChanged( |
+ CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); |
+} |
+ |
+// Verify that updating a non-Wallet profile or credit card will not send |
+// metadata to the sync server. |
+TEST(AutofillWalletMetadataSyncableServiceTest, IgnoreNonWalletDataUpdate) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 0, 0); |
+ local.SaveServerCard("card", 0, 0); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 0, 0); |
+ remote.SaveServerCard("card", 0, 0); |
+ |
+ MergeMetadata(&local, &remote); |
+ |
+ AutofillProfile profile; |
+ profile.set_use_count(1); |
+ profile.set_use_date(base::Time::FromInternalValue(2)); |
+ |
+ CreditCard card; |
+ card.set_use_count(3); |
+ card.set_use_date(base::Time::FromInternalValue(4)); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ local.AutofillProfileChanged(AutofillProfileChange( |
+ AutofillProfileChange::UPDATE, profile.guid(), &profile)); |
+ local.CreditCardChanged( |
+ CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); |
+} |
+ |
+// Verify that deleting or adding an individual Wallet address or credit card is |
+// ignored. (Sync should be notified only of "multiple autofill data changes" |
+// sent by the Wallet sync service.) |
+TEST(AutofillWalletMetadataSyncableServiceTest, IgnoreIndividualDataAddDelete) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr1", 0, 0); |
+ local.SaveServerProfile("addr2", 0, 0); |
+ local.SaveServerCard("card1", 0, 0); |
+ local.SaveServerCard("card2", 0, 0); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr1", 0, 0); |
+ remote.SaveServerProfile("addr2", 0, 0); |
+ remote.SaveServerCard("card1", 0, 0); |
+ remote.SaveServerCard("card2", 0, 0); |
+ |
+ MergeMetadata(&local, &remote); |
+ |
+ AutofillProfile profile1(AutofillProfile::SERVER_PROFILE, "addr1"); |
+ AutofillProfile profile2(AutofillProfile::SERVER_PROFILE, "addr2"); |
+ CreditCard card1(CreditCard::MASKED_SERVER_CARD, "card1"); |
+ CreditCard card2(CreditCard::FULL_SERVER_CARD, "card2"); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(_)).Times(0); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(_)).Times(0); |
+ |
+ local.AutofillProfileChanged(AutofillProfileChange( |
+ AutofillProfileChange::ADD, profile1.guid(), &profile1)); |
+ local.AutofillProfileChanged(AutofillProfileChange( |
+ AutofillProfileChange::REMOVE, profile2.guid(), nullptr)); |
+ local.CreditCardChanged( |
+ CreditCardChange(CreditCardChange::ADD, card1.guid(), &card1)); |
+ local.CreditCardChanged( |
+ CreditCardChange(CreditCardChange::REMOVE, card2.guid(), nullptr)); |
+} |
+ |
+// Verify that the sync server is notified of new metadata when Wallet data is |
+// added. |
+TEST(AutofillWalletMetadataSyncableServiceTest, NotifySyncServerNewMetadata) { |
+ NiceMock<MockAutofillWalletMetadataSyncableService> local; |
+ local.SaveServerProfile("addr", 0, 0); |
+ local.SaveServerCard("card", 0, 0); |
+ |
+ NiceMock<MockAutofillWalletMetadataSyncableService> remote; |
+ remote.SaveServerProfile("addr", 0, 0); |
+ remote.SaveServerCard("card", 0, 0); |
+ |
+ MergeMetadata(&local, &remote); |
+ |
+ local.SaveServerProfile("addr", 1, 2); |
+ local.SaveServerCard("card", 3, 4); |
+ |
+ EXPECT_CALL(remote, UpdateServerAddressUsageStats(Matches("addr", 1, 2))); |
+ EXPECT_CALL(remote, UpdateServerCardUsageStats(Matches("card", 3, 4))); |
+ |
+ local.AutofillMultipleChanged(); |
+} |
+ |
+} // namespace |
+} // namespace autofill |