blob: ff9742b84827cf94bb0e8de0656a27dc0ea1fbba [file] [log] [blame]
// Copyright 2015 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/browsing_data/core/counters/autofill_counter.h"
#include <array>
#include <memory>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/uuid.h"
#include "chrome/browser/autofill/autofill_entity_data_manager_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h"
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager_test_utils.h"
#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager_test_utils.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
#include "components/autofill/core/browser/data_model/payments/credit_card.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "components/autofill/core/browser/test_utils/test_autofill_clock.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/browsing_data/core/browsing_data_utils.h"
#include "components/browsing_data/core/counters/browsing_data_counter.h"
#include "components/browsing_data/core/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
namespace {
using browsing_data::AutofillCounter;
typedef base::test::TestFuture<
std::unique_ptr<browsing_data::BrowsingDataCounter::Result>>
CounterFuture;
class AutofillCounterTest : public InProcessBrowserTest {
public:
AutofillCounterTest() = default;
AutofillCounterTest(const AutofillCounterTest&) = delete;
AutofillCounterTest& operator=(const AutofillCounterTest&) = delete;
~AutofillCounterTest() override = default;
void SetUpOnMainThread() override {
personal_data_manager_ =
autofill::PersonalDataManagerFactory::GetForBrowserContext(
browser()->profile());
web_data_service_ = WebDataServiceFactory::GetAutofillWebDataForProfile(
browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS);
SetAutofillDeletionPref(true);
SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
}
void TearDownOnMainThread() override {
// Release our refs to let browser tear down of services complete in the
// same order as usual.
personal_data_manager_ = nullptr;
web_data_service_ = nullptr;
}
browsing_data::AutofillCounter GetCounter() {
return {GetPersonalDataManager(), GetWebDataService(),
GetEntityDataManager(), /*sync_service=*/nullptr};
}
// Autocomplete suggestions --------------------------------------------------
void AddAutocompleteSuggestion(const std::string& name,
const std::string& value) {
autofill::FormFieldData field;
field.set_name(base::ASCIIToUTF16(name));
field.set_value(base::ASCIIToUTF16(value));
std::vector<autofill::FormFieldData> form_fields;
form_fields.push_back(field);
web_data_service_->AddFormFields(form_fields);
}
void RemoveAutocompleteSuggestion(const std::string& name,
const std::string& value) {
web_data_service_->RemoveFormValueForElementName(
base::ASCIIToUTF16(name),
base::ASCIIToUTF16(value));
}
void ClearAutocompleteSuggestions() {
web_data_service_->RemoveFormElementsAddedBetween(
base::Time(), base::Time::Max());
}
// Credit cards --------------------------------------------------------------
void AddCreditCard(const char* card_number,
const char* exp_month,
const char* exp_year,
const char* billing_address_id) {
autofill::CreditCard card;
autofill::test::SetCreditCardInfo(&card, nullptr, card_number, exp_month,
exp_year, billing_address_id);
credit_card_ids_.push_back(card.guid());
personal_data_manager_->payments_data_manager().AddCreditCard(card);
autofill::PersonalDataChangedWaiter(*personal_data_manager_).Wait();
}
void RemoveLastCreditCard() {
personal_data_manager_->payments_data_manager().RemoveByGUID(
credit_card_ids_.back());
autofill::PersonalDataChangedWaiter(*personal_data_manager_).Wait();
credit_card_ids_.pop_back();
}
// Addresses -----------------------------------------------------------------
void AddAddress(const std::string& name,
const std::string& surname,
const std::string& address) {
autofill::AutofillProfile profile(
autofill::i18n_model_definition::kLegacyHierarchyCountryCode);
std::string id = base::Uuid::GenerateRandomV4().AsLowercaseString();
address_ids_.push_back(id);
profile.set_guid(id);
profile.SetInfo(autofill::NAME_FIRST, base::ASCIIToUTF16(name), "en-US");
profile.SetInfo(autofill::NAME_LAST, base::ASCIIToUTF16(surname), "en-US");
profile.SetInfo(autofill::ADDRESS_HOME_LINE1, base::ASCIIToUTF16(address),
"en-US");
personal_data_manager_->address_data_manager().AddProfile(profile);
autofill::PersonalDataChangedWaiter(*personal_data_manager_).Wait();
}
void RemoveLastAddress() {
personal_data_manager_->address_data_manager().RemoveProfile(
address_ids_.back());
autofill::PersonalDataChangedWaiter(*personal_data_manager_).Wait();
address_ids_.pop_back();
}
// Other autofill utils ------------------------------------------------------
void ClearCreditCardsAndAddresses() {
while (!credit_card_ids_.empty()) {
RemoveLastCreditCard();
}
while (!address_ids_.empty()) {
RemoveLastAddress();
}
}
// Other utils ---------------------------------------------------------------
void SetAutofillDeletionPref(bool value) {
browser()->profile()->GetPrefs()->SetBoolean(
browsing_data::prefs::kDeleteFormData, value);
}
void SetDeletionPeriodPref(browsing_data::TimePeriod period) {
browser()->profile()->GetPrefs()->SetInteger(
browsing_data::prefs::kDeleteTimePeriod, static_cast<int>(period));
}
autofill::EntityDataManager* GetEntityDataManager() {
return autofill::AutofillEntityDataManagerFactory::GetForProfile(
browser()->profile());
}
autofill::PersonalDataManager* GetPersonalDataManager() {
return personal_data_manager_;
}
scoped_refptr<autofill::AutofillWebDataService> GetWebDataService() {
return web_data_service_;
}
// Result retrieval ---------------------------------------------
browsing_data::BrowsingDataCounter::ResultInt GetNumSuggestions() {
return num_suggestions_;
}
browsing_data::BrowsingDataCounter::ResultInt GetNumCreditCards() {
return num_credit_cards_;
}
browsing_data::BrowsingDataCounter::ResultInt GetNumAddresses() {
return num_addresses_;
}
browsing_data::BrowsingDataCounter::ResultInt GetNumEntities() {
return num_entities_;
}
browsing_data::AutofillCounter::ResultInt GetCounterValue() {
return counter_value_;
}
void WaitForResult() {
std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result =
future.Take();
while (!result->Finished()) {
future.Clear();
result = future.Take();
}
AutofillCounter::AutofillResult* autofill_result =
static_cast<AutofillCounter::AutofillResult*>(result.get());
counter_value_ = autofill_result->Value();
num_credit_cards_ = autofill_result->num_credit_cards();
num_addresses_ = autofill_result->num_addresses();
num_entities_ = autofill_result->num_entities();
}
protected:
CounterFuture future;
private:
base::test::ScopedFeatureList feature_list_{
autofill::features::kAutofillAiWithDataSchema};
autofill::test::AutofillBrowserTestEnvironment autofill_test_environment_;
std::vector<std::string> credit_card_ids_;
std::vector<std::string> address_ids_;
std::unique_ptr<base::RunLoop> run_loop_;
raw_ptr<autofill::PersonalDataManager> personal_data_manager_;
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
browsing_data::BrowsingDataCounter::ResultInt counter_value_;
browsing_data::BrowsingDataCounter::ResultInt num_suggestions_;
browsing_data::BrowsingDataCounter::ResultInt num_credit_cards_;
browsing_data::BrowsingDataCounter::ResultInt num_addresses_;
browsing_data::BrowsingDataCounter::ResultInt num_entities_;
};
// Tests that we count the correct number of autocomplete suggestions.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, AutocompleteSuggestions) {
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(browser()->profile()->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetCounterValue());
AddAutocompleteSuggestion("email", "example@example.com");
counter.Restart();
WaitForResult();
EXPECT_EQ(1, GetCounterValue());
AddAutocompleteSuggestion("tel", "+123456789");
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetCounterValue());
AddAutocompleteSuggestion("tel", "+987654321");
counter.Restart();
WaitForResult();
EXPECT_EQ(3, GetCounterValue());
RemoveAutocompleteSuggestion("email", "example@example.com");
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetCounterValue());
ClearAutocompleteSuggestions();
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetCounterValue());
}
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Entities) {
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(browser()->profile()->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(GetNumEntities(), 0);
autofill::EntityInstance passport =
autofill::test::GetPassportEntityInstance();
GetEntityDataManager()->AddOrUpdateEntityInstance(passport);
autofill::EntityDataChangedWaiter(GetEntityDataManager()).Wait();
counter.Restart();
WaitForResult();
EXPECT_EQ(GetNumEntities(), 1);
autofill::EntityInstance drivers_license =
autofill::test::GetDriversLicenseEntityInstance();
GetEntityDataManager()->AddOrUpdateEntityInstance(drivers_license);
autofill::EntityDataChangedWaiter(GetEntityDataManager()).Wait();
counter.Restart();
WaitForResult();
EXPECT_EQ(GetNumEntities(), 2);
GetEntityDataManager()->RemoveEntityInstance(passport.guid());
autofill::EntityDataChangedWaiter(GetEntityDataManager()).Wait();
counter.Restart();
WaitForResult();
EXPECT_EQ(GetNumEntities(), 1);
}
// Tests that we count the correct number of credit cards.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, CreditCards) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetNumCreditCards());
AddCreditCard("0000-0000-0000-0000", "1", "2015", "1");
counter.Restart();
WaitForResult();
EXPECT_EQ(1, GetNumCreditCards());
AddCreditCard("0123-4567-8910-1112", "10", "2015", "1");
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetNumCreditCards());
AddCreditCard("1211-1098-7654-3210", "10", "2030", "1");
counter.Restart();
WaitForResult();
EXPECT_EQ(3, GetNumCreditCards());
RemoveLastCreditCard();
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetNumCreditCards());
ClearCreditCardsAndAddresses();
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetNumCreditCards());
}
// Tests that we count the correct number of addresses.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Addresses) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetNumAddresses());
AddAddress("John", "Doe", "Main Street 12345");
counter.Restart();
WaitForResult();
EXPECT_EQ(1, GetNumAddresses());
AddAddress("Jane", "Smith", "Main Street 12346");
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetNumAddresses());
AddAddress("John", "Smith", "Side Street 47");
counter.Restart();
WaitForResult();
EXPECT_EQ(3, GetNumAddresses());
RemoveLastAddress();
counter.Restart();
WaitForResult();
EXPECT_EQ(2, GetNumAddresses());
ClearCreditCardsAndAddresses();
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetNumAddresses());
}
// Tests that we return the correct complex result when counting more than
// one type of items.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, ComplexResult) {
AddAutocompleteSuggestion("email", "example@example.com");
AddAutocompleteSuggestion("zip", "12345");
AddAutocompleteSuggestion("tel", "+123456789");
AddAutocompleteSuggestion("tel", "+987654321");
AddAutocompleteSuggestion("city", "Munich");
AddCreditCard("0000-0000-0000-0000", "1", "2015", "1");
AddCreditCard("1211-1098-7654-3210", "10", "2030", "1");
AddAddress("John", "Doe", "Main Street 12345");
AddAddress("Jane", "Smith", "Main Street 12346");
AddAddress("John", "Smith", "Side Street 47");
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(5, GetCounterValue());
EXPECT_EQ(2, GetNumCreditCards());
EXPECT_EQ(3, GetNumAddresses());
}
// Tests that the counting respects time ranges.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
autofill::TestAutofillClock test_clock;
const base::Time kTime1 = base::Time::FromSecondsSinceUnixEpoch(25);
test_clock.SetNow(kTime1);
AddAutocompleteSuggestion("email", "example@example.com");
AddCreditCard("0000-0000-0000-0000", "1", "2015", "1");
AddAddress("John", "Doe", "Main Street 12345");
base::ThreadPoolInstance::Get()->FlushForTesting();
const base::Time kTime2 = kTime1 + base::Seconds(10);
test_clock.SetNow(kTime2);
AddCreditCard("0123-4567-8910-1112", "10", "2015", "1");
AddAddress("Jane", "Smith", "Main Street 12346");
AddAddress("John", "Smith", "Side Street 47");
base::ThreadPoolInstance::Get()->FlushForTesting();
const base::Time kTime3 = kTime2 + base::Seconds(10);
test_clock.SetNow(kTime3);
AddAutocompleteSuggestion("tel", "+987654321");
AddCreditCard("1211-1098-7654-3210", "10", "2030", "1");
base::ThreadPoolInstance::Get()->FlushForTesting();
// Test the results for different starting points.
struct TestCase {
const base::Time period_start;
const browsing_data::BrowsingDataCounter::ResultInt
expected_num_suggestions;
const browsing_data::BrowsingDataCounter::ResultInt
expected_num_credit_cards;
const browsing_data::BrowsingDataCounter::ResultInt expected_num_addresses;
};
auto test_cases = std::to_array<TestCase>({
{base::Time(), 2, 3, 3},
{kTime1, 2, 3, 3},
{kTime2, 1, 2, 2},
{kTime3, 1, 1, 0},
});
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter = GetCounter();
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
for (size_t i = 0; i < std::size(test_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test case %zu", i));
const auto& test_case = test_cases[i];
counter.SetPeriodStartForTesting(test_case.period_start);
counter.Restart();
WaitForResult();
EXPECT_EQ(test_case.expected_num_suggestions, GetCounterValue());
EXPECT_EQ(test_case.expected_num_credit_cards, GetNumCreditCards());
EXPECT_EQ(test_case.expected_num_addresses, GetNumAddresses());
future.Clear();
}
// Test the results for different ending points and base::Time as start.
counter.SetPeriodStartForTesting(base::Time());
counter.SetPeriodEndForTesting(kTime2);
counter.Restart();
WaitForResult();
EXPECT_EQ(1, GetCounterValue());
EXPECT_EQ(1, GetNumCreditCards());
EXPECT_EQ(1, GetNumAddresses());
counter.SetPeriodEndForTesting(kTime3);
counter.Restart();
WaitForResult();
EXPECT_EQ(1, GetCounterValue());
EXPECT_EQ(2, GetNumCreditCards());
EXPECT_EQ(3, GetNumAddresses());
}
} // namespace