blob: b1a9e5688dae4eb6e9a18afe0c2657096036eb6e [file] [log] [blame]
// Copyright 2012 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 <stddef.h>
#include <stdint.h>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/bind_test_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/browser_sync/abstract_profile_sync_service_test.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/driver/data_type_manager_impl.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "components/sync/driver/sync_client_mock.h"
#include "components/sync/driver/test_profile_sync_service.h"
#include "components/sync/engine/data_type_debug_info_listener.h"
#include "components/sync/engine/sequenced_model_worker.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/syncable/mutable_entry.h"
#include "components/sync/syncable/read_node.h"
#include "components/sync/syncable/read_transaction.h"
#include "components/sync/syncable/syncable_write_transaction.h"
#include "components/sync/syncable/write_node.h"
#include "components/sync/syncable/write_transaction.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/version_info/version_info.h"
#include "components/webdata/common/web_database.h"
#include "components/webdata_services/web_data_service_test_util.h"
#include "services/identity/public/cpp/identity_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using autofill::AutofillChange;
using autofill::AutofillChangeList;
using autofill::AutofillKey;
using autofill::AutofillProfile;
using autofill::AutofillProfileChange;
using autofill::AutofillProfileSyncableService;
using autofill::AutofillTable;
using autofill::AutofillWebDataService;
using autofill::NAME_FULL;
using autofill::PersonalDataManager;
using autofill::ServerFieldType;
using base::ASCIIToUTF16;
using base::Time;
using base::TimeDelta;
using base::WaitableEvent;
using syncer::AUTOFILL_PROFILE;
using syncer::BaseNode;
using syncer::syncable::CREATE;
using syncer::syncable::GET_TYPE_ROOT;
using syncer::syncable::MutableEntry;
using syncer::syncable::UNITTEST;
using syncer::syncable::WriterTag;
using syncer::syncable::WriteTransaction;
using testing::_;
using testing::ByMove;
using testing::DoAll;
using testing::ElementsAre;
using testing::Not;
using testing::Return;
using testing::SetArgPointee;
namespace browser_sync {
namespace {
void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled,
true);
registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled, true);
registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled,
true);
registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped,
atoi(version_info::GetVersionNumber().c_str()));
registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionValidated,
atoi(version_info::GetVersionNumber().c_str()));
registry->RegisterBooleanPref(
autofill::prefs::kAutofillJapanCityFieldMigrated, true);
registry->RegisterBooleanPref(autofill::prefs::kAutofillOrphanRowsRemoved,
true);
registry->RegisterIntegerPref(
autofill::prefs::kAutofillLastVersionDisusedAddressesDeleted, 0);
registry->RegisterIntegerPref(
autofill::prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0);
registry->RegisterStringPref(
autofill::prefs::kAutofillProfileValidity, "",
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
}
void RunAndSignal(base::OnceClosure cb, WaitableEvent* event) {
std::move(cb).Run();
event->Signal();
}
} // namespace
class AutofillTableMock : public AutofillTable {
public:
AutofillTableMock() {}
MOCK_METHOD2(RemoveFormElement,
bool(const base::string16& name,
const base::string16& value)); // NOLINT
MOCK_METHOD4(GetAutofillTimestamps,
bool(const base::string16& name, // NOLINT
const base::string16& value,
Time* date_created,
Time* date_last_used));
MOCK_METHOD1(GetAutofillProfiles,
bool(std::vector<std::unique_ptr<AutofillProfile>>*)); // NOLINT
MOCK_METHOD1(UpdateAutofillProfile, bool(const AutofillProfile&)); // NOLINT
MOCK_METHOD1(AddAutofillProfile, bool(const AutofillProfile&)); // NOLINT
MOCK_METHOD1(RemoveAutofillProfile, bool(const std::string&)); // NOLINT
// TODO(crbug.com/904390): Remove when the investigation is over.
MOCK_CONST_METHOD1(
GetServerProfiles,
bool(std::vector<std::unique_ptr<AutofillProfile>>*)); // NOLINT
};
MATCHER_P(MatchProfiles, profile, "") {
return (profile.Compare(arg) == 0);
}
ACTION_P(LoadAutofillProfiles, datafunc) {
std::vector<std::unique_ptr<AutofillProfile>> profiles =
std::move(datafunc());
arg0->swap(profiles);
}
class WebDatabaseFake : public WebDatabase {
public:
explicit WebDatabaseFake(AutofillTable* autofill_table) {
AddTable(autofill_table);
}
};
class FakeAutofillBackend : public autofill::AutofillWebDataBackend {
public:
FakeAutofillBackend(
WebDatabase* web_database,
const base::RepeatingClosure& on_changed,
const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started,
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner)
: web_database_(web_database),
on_changed_(on_changed),
on_sync_started_(on_sync_started),
ui_task_runner_(ui_task_runner) {}
~FakeAutofillBackend() override {}
WebDatabase* GetDatabase() override { return web_database_; }
void AddObserver(
autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
}
void RemoveObserver(
autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
}
void CommitChanges() override {}
void NotifyOfAutofillProfileChanged(
const autofill::AutofillProfileChange& change) override {}
void NotifyOfCreditCardChanged(
const autofill::CreditCardChange& change) override {}
void NotifyOfMultipleAutofillChanges() override {
DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
ui_task_runner_->PostTask(FROM_HERE, on_changed_);
}
void NotifyOfAddressConversionCompleted() override {}
void NotifyThatSyncHasStarted(syncer::ModelType model_type) override {
DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
ui_task_runner_->PostTask(FROM_HERE,
base::BindOnce(on_sync_started_, model_type));
}
private:
WebDatabase* web_database_;
base::RepeatingClosure on_changed_;
base::RepeatingCallback<void(syncer::ModelType)> on_sync_started_;
const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
};
class ProfileSyncServiceAutofillTest;
class TokenWebDataServiceFake : public TokenWebData {
public:
TokenWebDataServiceFake(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
: TokenWebData(ui_task_runner, db_task_runner) {}
bool IsDatabaseLoaded() override { return true; }
AutofillWebDataService::Handle GetAllTokens(
WebDataServiceConsumer* consumer) override {
// TODO(tim): It would be nice if WebDataService was injected on
// construction of ProfileOAuth2TokenService rather than fetched by
// Initialize so that this isn't necessary (we could pass a null service).
// We currently do return it via EXPECT_CALLs, but without depending on
// order-of-initialization (which seems way more fragile) we can't tell
// which component is asking at what time, and some components in these
// Autofill tests require a WebDataService.
return 0;
}
private:
~TokenWebDataServiceFake() override {}
DISALLOW_COPY_AND_ASSIGN(TokenWebDataServiceFake);
};
class WebDataServiceFake : public AutofillWebDataService {
public:
WebDataServiceFake(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
: AutofillWebDataService(ui_task_runner, db_task_runner),
web_database_(nullptr),
autofill_profile_syncable_service_(nullptr),
syncable_service_created_or_destroyed_(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED),
db_task_runner_(db_task_runner),
ui_task_runner_(ui_task_runner) {}
void SetDatabase(WebDatabase* web_database) { web_database_ = web_database; }
void StartSyncableService() {
// The |autofill_profile_syncable_service_| must be constructed on the DB
// sequence.
const base::RepeatingClosure& on_changed_callback = base::BindRepeating(
&WebDataServiceFake::NotifyAutofillMultipleChangedOnUISequence,
AsWeakPtr());
const base::RepeatingCallback<void(syncer::ModelType)>&
on_sync_started_callback = base::BindRepeating(
&WebDataServiceFake::NotifySyncStartedOnUISequence, AsWeakPtr());
db_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WebDataServiceFake::CreateSyncableService,
base::Unretained(this), on_changed_callback,
std::move(on_sync_started_callback)));
syncable_service_created_or_destroyed_.Wait();
}
void ShutdownSyncableService() {
// The |autofill_profile_syncable_service_| must be destructed on the DB
// sequence.
db_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WebDataServiceFake::DestroySyncableService,
base::Unretained(this)));
syncable_service_created_or_destroyed_.Wait();
}
bool IsDatabaseLoaded() override { return true; }
WebDatabase* GetDatabase() override { return web_database_; }
void OnAutofillProfileChanged(const AutofillProfileChange& changes) {
WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
base::OnceClosure notify_cb = base::BindOnce(
&AutofillProfileSyncableService::AutofillProfileChanged,
base::Unretained(autofill_profile_syncable_service_), changes);
db_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&RunAndSignal, std::move(notify_cb), &event));
event.Wait();
}
private:
~WebDataServiceFake() override {}
void CreateSyncableService(
const base::RepeatingClosure& on_changed_callback,
const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started) {
ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
// These services are deleted in DestroySyncableService().
backend_ = std::make_unique<FakeAutofillBackend>(
GetDatabase(), on_changed_callback, on_sync_started,
ui_task_runner_.get());
AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
this, backend_.get(), "en-US");
autofill_profile_syncable_service_ =
AutofillProfileSyncableService::FromWebDataService(this);
syncable_service_created_or_destroyed_.Signal();
}
void DestroySyncableService() {
ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
autofill_profile_syncable_service_ = nullptr;
backend_.reset();
syncable_service_created_or_destroyed_.Signal();
}
WebDatabase* web_database_;
AutofillProfileSyncableService* autofill_profile_syncable_service_;
std::unique_ptr<autofill::AutofillWebDataBackend> backend_;
WaitableEvent syncable_service_created_or_destroyed_;
const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
};
ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) {
return std::make_unique<syncer::DataTypeManagerImpl>(arg0, debug_listener,
arg2, arg3, arg4, arg5);
}
class MockPersonalDataManager : public PersonalDataManager {
public:
MockPersonalDataManager() : PersonalDataManager("en-US") {}
MOCK_CONST_METHOD0(IsDataLoaded, bool());
MOCK_METHOD0(LoadProfiles, void());
MOCK_METHOD0(LoadCreditCards, void());
MOCK_METHOD0(LoadPaymentsCustomerData, void());
MOCK_METHOD0(Refresh, void());
};
class AddAutofillProfileHelper;
class ProfileSyncServiceAutofillTest
: public AbstractProfileSyncServiceTest,
public syncer::DataTypeDebugInfoListener {
public:
// DataTypeDebugInfoListener implementation.
void OnDataTypeConfigureComplete(
const std::vector<syncer::DataTypeConfigurationStats>&
configuration_stats) override {
for (const syncer::DataTypeConfigurationStats& stat : configuration_stats) {
if (stat.model_type == syncer::AUTOFILL_PROFILE) {
association_stats_ = stat.association_stats;
return;
}
}
ASSERT_TRUE(false) << "Autofill profile type did not get configured!";
}
protected:
ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) {
autofill::CountryNames::SetLocaleString("en-US");
RegisterAutofillPrefs(
profile_sync_service_bundle()->pref_service()->registry());
data_type_thread()->Start();
web_database_ = std::make_unique<WebDatabaseFake>(&autofill_table_);
web_data_wrapper_ = std::make_unique<MockWebDataServiceWrapper>(
new WebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
data_type_thread()->task_runner()),
new TokenWebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
data_type_thread()->task_runner()));
web_data_service_ = static_cast<WebDataServiceFake*>(
web_data_wrapper_->GetProfileAutofillWebData().get());
web_data_service_->SetDatabase(web_database_.get());
personal_data_manager_ = std::make_unique<MockPersonalDataManager>();
EXPECT_CALL(personal_data_manager(), LoadProfiles());
EXPECT_CALL(personal_data_manager(), LoadCreditCards());
EXPECT_CALL(personal_data_manager(), LoadPaymentsCustomerData());
personal_data_manager_->Init(web_data_service_,
/*account_database=*/nullptr,
profile_sync_service_bundle()->pref_service(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*is_off_the_record=*/false);
web_data_service_->StartSyncableService();
}
~ProfileSyncServiceAutofillTest() override {
web_data_service_->ShutdownOnUISequence();
web_data_service_->ShutdownSyncableService();
web_data_wrapper_->Shutdown();
web_data_service_ = nullptr;
web_data_wrapper_.reset();
web_database_.reset();
// Shut down the service explicitly before some data members from this
// test it needs will be deleted.
sync_service()->Shutdown();
}
int GetSyncCount() {
syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
syncer::ReadNode node(&trans);
if (node.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK)
return 0;
return node.GetTotalNodeCount() - 1;
}
void StartAutofillProfileSyncService(base::OnceClosure callback) {
profile_sync_service_bundle()
->identity_test_env()
->MakePrimaryAccountAvailable("test_user@gmail.com");
std::unique_ptr<syncer::SyncClientMock> sync_client =
profile_sync_service_bundle()->CreateSyncClientMock();
syncer::SyncClientMock* sync_client_copy = sync_client.get();
CreateSyncService(std::move(sync_client), std::move(callback));
syncer::DataTypeController::TypeVector controllers;
controllers.push_back(std::make_unique<AutofillProfileDataTypeController>(
data_type_thread()->task_runner(), /*dump_stack=*/base::DoNothing(),
sync_service(), sync_client_copy,
base::BindLambdaForTesting([&]() -> autofill::PersonalDataManager* {
return personal_data_manager_.get();
}),
web_data_service_));
ON_CALL(*sync_client_copy, GetSyncableServiceForType(AUTOFILL_PROFILE))
.WillByDefault(testing::Invoke([=](syncer::ModelType) {
return AutofillProfileSyncableService::FromWebDataService(
web_data_service_.get())
->AsWeakPtr();
}));
ON_CALL(*sync_client_copy, CreateDataTypeControllers(_))
.WillByDefault(Return(ByMove(std::move(controllers))));
ON_CALL(*sync_client_copy, CreateModelWorkerForGroup(syncer::GROUP_DB))
.WillByDefault(
Return(base::MakeRefCounted<syncer::SequencedModelWorker>(
data_type_thread()->task_runner(), syncer::GROUP_DB)));
ON_CALL(*profile_sync_service_bundle()->component_factory(),
CreateDataTypeManager(_, _, _, _, _, _))
.WillByDefault(ReturnNewDataTypeManagerWithDebugListener(
syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));
EXPECT_CALL(personal_data_manager(), IsDataLoaded())
.WillRepeatedly(Return(true));
sync_service()->Initialize();
base::RunLoop().Run();
// It's possible this test triggered an unrecoverable error, in which case
// we can't get the sync count.
if (sync_service()->IsSyncFeatureActive()) {
EXPECT_EQ(GetSyncCount(),
association_stats_.num_sync_items_after_association);
}
EXPECT_EQ(association_stats_.num_sync_items_after_association,
association_stats_.num_sync_items_before_association +
association_stats_.num_sync_items_added -
association_stats_.num_sync_items_deleted);
}
bool AddAutofillSyncNode(const AutofillProfile& profile) {
syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
syncer::WriteNode node(&trans);
std::string tag = profile.guid();
syncer::WriteNode::InitUniqueByCreationResult result =
node.InitUniqueByCreation(AUTOFILL_PROFILE, tag);
if (result != syncer::WriteNode::INIT_SUCCESS)
return false;
sync_pb::EntitySpecifics specifics;
AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics);
node.SetEntitySpecifics(specifics);
return true;
}
bool GetAutofillProfilesFromSyncDBUnderProfileNode(
std::vector<AutofillProfile>* profiles) {
syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
syncer::ReadNode autofill_root(&trans);
if (autofill_root.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK) {
return false;
}
int64_t child_id = autofill_root.GetFirstChildId();
while (child_id != syncer::kInvalidId) {
syncer::ReadNode child_node(&trans);
if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
return false;
const sync_pb::AutofillProfileSpecifics& autofill(
child_node.GetEntitySpecifics().autofill_profile());
AutofillProfile p;
p.set_guid(autofill.guid());
AutofillProfileSyncableService::OverwriteProfileWithServerData(autofill,
&p);
profiles->push_back(p);
child_id = child_node.GetSuccessorId();
}
return true;
}
void SetIdleChangeProcessorExpectations() {
EXPECT_CALL(autofill_table_, RemoveFormElement(_, _)).Times(0);
EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _, _)).Times(0);
}
AutofillTableMock& autofill_table() { return autofill_table_; }
MockPersonalDataManager& personal_data_manager() {
return *personal_data_manager_;
}
WebDataServiceFake* web_data_service() { return web_data_service_.get(); }
private:
friend class AddAutofillProfileHelper;
AutofillTableMock autofill_table_;
std::unique_ptr<WebDatabaseFake> web_database_;
std::unique_ptr<MockWebDataServiceWrapper> web_data_wrapper_;
scoped_refptr<WebDataServiceFake> web_data_service_;
std::unique_ptr<MockPersonalDataManager> personal_data_manager_;
syncer::DataTypeAssociationStats association_stats_;
base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
};
class AddAutofillProfileHelper {
public:
AddAutofillProfileHelper(ProfileSyncServiceAutofillTest* test,
const std::vector<AutofillProfile>& entries)
: callback_(base::BindOnce(&AddAutofillProfileHelper::AddAutofillCallback,
base::Unretained(this),
test,
entries)),
success_(false) {}
base::OnceClosure callback() { return std::move(callback_); }
bool success() { return success_; }
private:
void AddAutofillCallback(ProfileSyncServiceAutofillTest* test,
const std::vector<AutofillProfile>& entries) {
if (!test->CreateRoot(AUTOFILL_PROFILE))
return;
for (size_t i = 0; i < entries.size(); ++i) {
if (!test->AddAutofillSyncNode(entries[i]))
return;
}
success_ = true;
}
base::OnceClosure callback_;
bool success_;
};
TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
std::vector<AutofillProfile> expected_profiles;
std::unique_ptr<AutofillProfile> profile0 =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
profile0.get(), "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
expected_profiles.push_back(*profile0);
profiles.push_back(std::move(profile0));
auto profile_returner = [&profiles]() { return std::move(profiles); };
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
EXPECT_CALL(personal_data_manager(), Refresh());
SetIdleChangeProcessorExpectations();
CreateRootHelper create_root(this, AUTOFILL_PROFILE);
StartAutofillProfileSyncService(create_root.callback());
ASSERT_TRUE(create_root.success());
std::vector<AutofillProfile> sync_profiles;
ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(&sync_profiles));
EXPECT_EQ(1U, sync_profiles.size());
EXPECT_EQ(0, expected_profiles[0].Compare(sync_profiles[0]));
}
TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(autofill_table(),
UpdateAutofillProfile(MatchProfiles(sync_profile)))
.WillOnce(Return(true));
EXPECT_CALL(personal_data_manager(), Refresh());
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(1U, new_sync_profiles.size());
EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
}
// Tests that a sync with a new native profile that matches a more recent new
// sync profile but with less information results in the native profile being
// deleted and replaced by the sync profile with merged usage stats.
TEST_F(
ProfileSyncServiceAutofillTest,
HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndMoreRecent) {
// Create two almost identical profiles. The GUIDs are different and the
// native profile has no value for company name.
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
native_profile->set_use_date(base::Time::FromTimeT(1234));
AutofillProfile expected_profile(sync_profile);
expected_profile.SetRawInfo(NAME_FULL,
ASCIIToUTF16("Billing Mitchell Morrison"));
expected_profile.set_use_count(1);
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
EXPECT_CALL(autofill_table(),
AddAutofillProfile(MatchProfiles(expected_profile)))
.WillOnce(Return(true));
EXPECT_CALL(autofill_table(),
RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
.WillOnce(Return(true));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(personal_data_manager(), Refresh());
// Adds all entries in |sync_profiles| to sync.
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(1U, new_sync_profiles.size());
// Check that key fields are the same.
EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
// Make sure the additional information from the sync profile was kept.
EXPECT_EQ(ASCIIToUTF16("Fox"),
new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
// Check that the latest use date is saved.
EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
// Check that the use counts were added (default value is 1).
EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}
// Tests that a sync with a new native profile that matches an older new sync
// profile but with less information results in the native profile being deleted
// and replaced by the sync profile with merged usage stats.
TEST_F(ProfileSyncServiceAutofillTest,
HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndOlder) {
// Create two almost identical profiles. The GUIDs are different and the
// native profile has no value for company name.
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
sync_profile.set_use_date(base::Time::FromTimeT(1234));
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
native_profile->set_use_date(base::Time::FromTimeT(4321));
AutofillProfile expected_profile(sync_profile);
expected_profile.SetRawInfo(NAME_FULL,
ASCIIToUTF16("Billing Mitchell Morrison"));
expected_profile.set_use_count(1);
expected_profile.set_use_date(native_profile->use_date());
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
EXPECT_CALL(autofill_table(),
AddAutofillProfile(MatchProfiles(expected_profile)))
.WillOnce(Return(true));
EXPECT_CALL(autofill_table(),
RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
.WillOnce(Return(true));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(personal_data_manager(), Refresh());
// Adds all entries in |sync_profiles| to sync.
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(1U, new_sync_profiles.size());
// Check that key fields are the same.
EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
// Make sure the additional information from the sync profile was kept.
EXPECT_EQ(ASCIIToUTF16("Fox"),
new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
// Check that the latest use date is saved.
EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
// Check that the use counts were added (default value is 1).
EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}
// Tests that a sync with a new native profile that matches an a new sync
// profile but with more information results in the native profile being deleted
// and replaced by the sync profile with the native profiles additional
// information merged in. The merge should happen even if the sync profile is
// more recent.
TEST_F(ProfileSyncServiceAutofillTest,
HasNativeHasSyncMergeSimilarProfileCombine_NativeHasMoreInfo) {
// Create two almost identical profiles. The GUIDs are different and the
// sync profile has no value for company name.
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
native_profile->set_use_date(base::Time::FromTimeT(1234));
AutofillProfile expected_profile(*native_profile);
expected_profile.SetRawInfo(NAME_FULL,
ASCIIToUTF16("Billing Mitchell Morrison"));
expected_profile.set_use_date(sync_profile.use_date());
expected_profile.set_use_count(1);
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
EXPECT_CALL(autofill_table(),
AddAutofillProfile(MatchProfiles(expected_profile)))
.WillOnce(Return(true));
EXPECT_CALL(autofill_table(),
RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
.WillOnce(Return(true));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(personal_data_manager(), Refresh());
// Adds all entries in |sync_profiles| to sync.
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(1U, new_sync_profiles.size());
// Check that key fields are the same.
EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(expected_profile, "en-US"));
// Make sure the additional information of the native profile was saved into
// the sync profile.
EXPECT_EQ(ASCIIToUTF16("Fox"),
new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
// Check that the latest use date is saved.
EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
// Check that the use counts were added (default value is 1).
EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}
// Tests that a sync with a new native profile that differ only by name a new
// sync profile results in keeping both profiles.
TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSync_DifferentPrimaryInfo) {
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"John", "Smith", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
native_profile->set_use_date(base::Time::FromTimeT(1234));
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
EXPECT_CALL(autofill_table(), AddAutofillProfile(MatchProfiles(sync_profile)))
.WillOnce(Return(true));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(personal_data_manager(), Refresh());
// Adds all entries in |sync_profiles| to sync.
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
// The two profiles should be kept.
ASSERT_EQ(2U, new_sync_profiles.size());
}
// Tests that a new native profile that is the same as a new sync profile except
// with different GUIDs results in the native profile being deleted and replaced
// by the sync profile.
TEST_F(ProfileSyncServiceAutofillTest, MergeProfileWithDifferentGuid) {
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
sync_profile.set_use_count(20);
sync_profile.set_use_date(base::Time::FromTimeT(1234));
std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), native_guid.c_str(), "Billing", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
native_profile->set_use_count(5);
native_profile->set_use_date(base::Time::FromTimeT(4321));
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(autofill_table(), AddAutofillProfile(_)).WillOnce(Return(true));
EXPECT_CALL(autofill_table(), RemoveAutofillProfile(native_guid))
.WillOnce(Return(true));
EXPECT_CALL(personal_data_manager(), Refresh());
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
// Check that the profiles were merged.
ASSERT_EQ(1U, new_sync_profiles.size());
EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
// Check that the sync guid was kept.
EXPECT_EQ(sync_profile.guid(), new_sync_profiles[0].guid());
// Check that the sync profile use count was kept.
EXPECT_EQ(20U, new_sync_profiles[0].use_count());
// Check that the sync profile use date was kept.
EXPECT_EQ(base::Time::FromTimeT(1234), new_sync_profiles[0].use_date());
}
TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddProfile) {
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).WillOnce(Return(true));
EXPECT_CALL(personal_data_manager(), Refresh());
SetIdleChangeProcessorExpectations();
CreateRootHelper create_root(this, AUTOFILL_PROFILE);
StartAutofillProfileSyncService(create_root.callback());
ASSERT_TRUE(create_root.success());
AutofillProfile added_profile;
autofill::test::SetProfileInfoWithGuid(
&added_profile, "D6ADA912-D374-4C0A-917D-F5C8EBE43011", "Josephine",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
// TODO(crbug.com/904390): Remove when the investigation is over. This call is
// needed in the AutofillProfileChanged() callback.
EXPECT_CALL(autofill_table(), GetServerProfiles(_)).WillOnce(Return(true));
AutofillProfileChange change(AutofillProfileChange::ADD, added_profile.guid(),
&added_profile);
web_data_service()->OnAutofillProfileChanged(change);
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(1U, new_sync_profiles.size());
EXPECT_EQ(0, added_profile.Compare(new_sync_profiles[0]));
}
TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
AutofillProfile sync_profile;
autofill::test::SetProfileInfoWithGuid(
&sync_profile, "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
std::unique_ptr<AutofillProfile> native_profile =
std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
native_profiles.push_back(std::move(native_profile));
auto profile_returner = [&native_profiles]() {
return std::move(native_profiles);
};
EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
.WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
std::vector<AutofillProfile> sync_profiles;
sync_profiles.push_back(sync_profile);
AddAutofillProfileHelper add_autofill(this, sync_profiles);
EXPECT_CALL(personal_data_manager(), Refresh());
StartAutofillProfileSyncService(add_autofill.callback());
ASSERT_TRUE(add_autofill.success());
AutofillProfileChange change(AutofillProfileChange::REMOVE,
sync_profile.guid(), &sync_profile);
web_data_service()->OnAutofillProfileChanged(change);
std::vector<AutofillProfile> new_sync_profiles;
ASSERT_TRUE(
GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
ASSERT_EQ(0U, new_sync_profiles.size());
}
} // namespace browser_sync