| // 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/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/country_names.h" |
| #include "components/autofill/core/browser/field_types.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h" |
| #include "components/autofill/core/browser/webdata/autofill_change.h" |
| #include "components/autofill/core/browser/webdata/autofill_data_type_controller.h" |
| #include "components/autofill/core/browser/webdata/autofill_entry.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_pref_names.h" |
| #include "components/browser_sync/abstract_profile_sync_service_test.h" |
| #include "components/browser_sync/profile_sync_service.h" |
| #include "components/browser_sync/test_profile_sync_service.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/sync_api_component_factory_mock.h" |
| #include "components/sync/engine/data_type_debug_info_listener.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 "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using autofill::AutocompleteSyncableService; |
| using autofill::AutofillChange; |
| using autofill::AutofillChangeList; |
| using autofill::AutofillEntry; |
| 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; |
| 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::DoAll; |
| using testing::ElementsAre; |
| using testing::Not; |
| using testing::SetArgPointee; |
| using testing::Return; |
| |
| namespace browser_sync { |
| |
| namespace { |
| |
| void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) { |
| registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled, |
| true); |
| registry->RegisterBooleanPref(autofill::prefs::kAutofillEnabled, true); |
| registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled, |
| true); |
| registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileUseDatesFixed, |
| true); |
| registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped, |
| atoi(version_info::GetVersionNumber().c_str())); |
| registry->RegisterDoublePref(autofill::prefs::kAutofillBillingCustomerNumber, |
| 0.0); |
| } |
| |
| void RunAndSignal(const base::Closure& cb, WaitableEvent* event) { |
| cb.Run(); |
| event->Signal(); |
| } |
| |
| AutofillEntry MakeAutofillEntry(const std::string& name, |
| const std::string& value, |
| int time_shift0, |
| int time_shift1) { |
| // Time deep in the past would cause Autocomplete sync to discard the |
| // entries. |
| static Time base_time = Time::Now().LocalMidnight(); |
| |
| Time date_created = base_time + TimeDelta::FromSeconds(time_shift0); |
| Time date_last_used = date_created; |
| if (time_shift1 >= 0) |
| date_last_used = base_time + TimeDelta::FromSeconds(time_shift1); |
| return AutofillEntry(AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), |
| date_created, date_last_used); |
| } |
| |
| AutofillEntry MakeAutofillEntry(const std::string& name, |
| const std::string& value, |
| int time_shift) { |
| return MakeAutofillEntry(name, value, time_shift, -1); |
| } |
| |
| } // namespace |
| |
| class AutofillTableMock : public AutofillTable { |
| public: |
| AutofillTableMock() {} |
| MOCK_METHOD2(RemoveFormElement, |
| bool(const base::string16& name, |
| const base::string16& value)); // NOLINT |
| MOCK_METHOD1(GetAllAutofillEntries, |
| bool(std::vector<AutofillEntry>* entries)); // NOLINT |
| MOCK_METHOD4(GetAutofillTimestamps, |
| bool(const base::string16& name, // NOLINT |
| const base::string16& value, |
| Time* date_created, |
| Time* date_last_used)); |
| MOCK_METHOD1(UpdateAutofillEntries, |
| bool(const std::vector<AutofillEntry>&)); // NOLINT |
| 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 |
| }; |
| |
| 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 MockAutofillBackend : public autofill::AutofillWebDataBackend { |
| public: |
| MockAutofillBackend( |
| WebDatabase* web_database, |
| const base::Closure& on_changed, |
| const base::Callback<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) {} |
| |
| ~MockAutofillBackend() override {} |
| WebDatabase* GetDatabase() override { return web_database_; } |
| void AddObserver( |
| autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override { |
| } |
| void RemoveObserver( |
| autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override { |
| } |
| void RemoveExpiredFormElements() override {} |
| void NotifyOfMultipleAutofillChanges() override { |
| DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence()); |
| ui_task_runner_->PostTask(FROM_HERE, on_changed_); |
| } |
| void NotifyThatSyncHasStarted(syncer::ModelType model_type) override { |
| DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence()); |
| ui_task_runner_->PostTask(FROM_HERE, |
| base::Bind(on_sync_started_, model_type)); |
| } |
| |
| private: |
| WebDatabase* web_database_; |
| base::Closure on_changed_; |
| base::Callback<void(syncer::ModelType)> on_sync_started_; |
| const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; |
| }; |
| |
| class ProfileSyncServiceAutofillTest; |
| |
| template <class AutofillProfile> |
| syncer::ModelType GetModelType() { |
| return syncer::UNSPECIFIED; |
| } |
| |
| template <> |
| syncer::ModelType GetModelType<AutofillEntry>() { |
| return AUTOFILL; |
| } |
| |
| template <> |
| syncer::ModelType GetModelType<AutofillProfile>() { |
| return AUTOFILL_PROFILE; |
| } |
| |
| 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), |
| autocomplete_syncable_service_(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::Closure& on_changed_callback = base::Bind( |
| &WebDataServiceFake::NotifyAutofillMultipleChangedOnUISequence, |
| AsWeakPtr()); |
| const base::Callback<void(syncer::ModelType)> on_sync_started_callback = |
| base::Bind(&WebDataServiceFake::NotifySyncStartedOnUISequence, |
| AsWeakPtr()); |
| |
| db_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&WebDataServiceFake::CreateSyncableService, |
| base::Unretained(this), on_changed_callback, |
| 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::Bind(&WebDataServiceFake::DestroySyncableService, |
| base::Unretained(this))); |
| syncable_service_created_or_destroyed_.Wait(); |
| } |
| |
| bool IsDatabaseLoaded() override { return true; } |
| |
| WebDatabase* GetDatabase() override { return web_database_; } |
| |
| void OnAutofillEntriesChanged(const AutofillChangeList& changes) { |
| WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| |
| base::Closure notify_cb = |
| base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged, |
| base::Unretained(autocomplete_syncable_service_), changes); |
| db_task_runner_->PostTask(FROM_HERE, |
| base::Bind(&RunAndSignal, notify_cb, &event)); |
| event.Wait(); |
| } |
| |
| void OnAutofillProfileChanged(const AutofillProfileChange& changes) { |
| WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| |
| base::Closure notify_cb = base::Bind( |
| &AutocompleteSyncableService::AutofillProfileChanged, |
| base::Unretained(autofill_profile_syncable_service_), changes); |
| db_task_runner_->PostTask(FROM_HERE, |
| base::Bind(&RunAndSignal, notify_cb, &event)); |
| event.Wait(); |
| } |
| |
| private: |
| ~WebDataServiceFake() override {} |
| |
| void CreateSyncableService( |
| const base::Closure& on_changed_callback, |
| const base::Callback<void(syncer::ModelType)>& on_sync_started) { |
| ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence()); |
| // These services are deleted in DestroySyncableService(). |
| backend_ = std::make_unique<MockAutofillBackend>( |
| GetDatabase(), on_changed_callback, on_sync_started, |
| ui_task_runner_.get()); |
| AutocompleteSyncableService::CreateForWebDataServiceAndBackend( |
| this, backend_.get()); |
| AutofillProfileSyncableService::CreateForWebDataServiceAndBackend( |
| this, backend_.get(), "en-US"); |
| |
| autocomplete_syncable_service_ = |
| AutocompleteSyncableService::FromWebDataService(this); |
| autofill_profile_syncable_service_ = |
| AutofillProfileSyncableService::FromWebDataService(this); |
| |
| syncable_service_created_or_destroyed_.Signal(); |
| } |
| |
| void DestroySyncableService() { |
| ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence()); |
| autocomplete_syncable_service_ = nullptr; |
| autofill_profile_syncable_service_ = nullptr; |
| backend_.reset(); |
| syncable_service_created_or_destroyed_.Signal(); |
| } |
| |
| WebDatabase* web_database_; |
| AutocompleteSyncableService* autocomplete_syncable_service_; |
| 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_P2(ReturnNewDataTypeManagerWithDebugListener, |
| sync_client, |
| debug_listener) { |
| return new syncer::DataTypeManagerImpl(sync_client, 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(Refresh, void()); |
| }; |
| |
| template <class T> |
| class AddAutofillHelper; |
| |
| class ProfileSyncServiceAutofillTest |
| : public AbstractProfileSyncServiceTest, |
| public syncer::DataTypeDebugInfoListener { |
| public: |
| // DataTypeDebugInfoListener implementation. |
| void OnDataTypeConfigureComplete( |
| const std::vector<syncer::DataTypeConfigurationStats>& |
| configuration_stats) override { |
| ASSERT_EQ(1u, configuration_stats.size()); |
| association_stats_ = configuration_stats[0].association_stats; |
| } |
| |
| protected: |
| ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) { |
| autofill::CountryNames::SetLocaleString("en-US"); |
| RegisterAutofillPrefs( |
| profile_sync_service_bundle()->pref_service()->registry()); |
| |
| data_type_thread()->Start(); |
| profile_sync_service_bundle()->set_db_thread( |
| data_type_thread()->task_runner()); |
| |
| 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_->GetAutofillWebData().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()); |
| |
| personal_data_manager_->Init( |
| web_data_service_, profile_sync_service_bundle()->pref_service(), |
| profile_sync_service_bundle()->account_tracker(), |
| profile_sync_service_bundle()->signin_manager(), false); |
| |
| web_data_service_->StartSyncableService(); |
| |
| ProfileSyncServiceBundle::SyncClientBuilder builder( |
| profile_sync_service_bundle()); |
| builder.SetPersonalDataManager(personal_data_manager_.get()); |
| builder.SetSyncServiceCallback(GetSyncServiceCallback()); |
| builder.SetSyncableServiceCallback( |
| base::Bind(&ProfileSyncServiceAutofillTest::GetSyncableServiceForType, |
| base::Unretained(this))); |
| builder.set_activate_model_creation(); |
| sync_client_owned_ = builder.Build(); |
| sync_client_ = sync_client_owned_.get(); |
| |
| // When UpdateAutofillEntries() is called with an empty list, the return |
| // value should be |true|, rather than the default of |false|. |
| std::vector<AutofillEntry> empty; |
| EXPECT_CALL(autofill_table_, UpdateAutofillEntries(empty)) |
| .WillRepeatedly(Return(true)); |
| } |
| |
| ~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::ModelType type) { |
| syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare()); |
| syncer::ReadNode node(&trans); |
| if (node.InitTypeRoot(type) != BaseNode::INIT_OK) |
| return 0; |
| return node.GetTotalNodeCount() - 1; |
| } |
| |
| void StartSyncService(const base::Closure& callback, |
| bool will_fail_association, |
| syncer::ModelType type) { |
| SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager(); |
| signin->SetAuthenticatedAccountInfo("12345", "test_user@gmail.com"); |
| CreateSyncService(std::move(sync_client_owned_), callback); |
| |
| EXPECT_CALL(*profile_sync_service_bundle()->component_factory(), |
| CreateDataTypeManager(_, _, _, _, _, _)) |
| .WillOnce(ReturnNewDataTypeManagerWithDebugListener( |
| sync_client_, |
| syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr()))); |
| |
| EXPECT_CALL(personal_data_manager(), IsDataLoaded()) |
| .WillRepeatedly(Return(true)); |
| |
| // We need tokens to get the tests going |
| profile_sync_service_bundle()->auth_service()->UpdateCredentials( |
| signin->GetAuthenticatedAccountId(), "oauth2_login_token"); |
| |
| sync_service()->RegisterDataTypeController(CreateDataTypeController(type)); |
| 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()->IsSyncActive()) { |
| EXPECT_EQ(GetSyncCount(type), |
| 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 AutofillEntry& entry) { |
| syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare()); |
| syncer::WriteNode node(&trans); |
| std::string tag = AutocompleteSyncableService::KeyToTag( |
| base::UTF16ToUTF8(entry.key().name()), |
| base::UTF16ToUTF8(entry.key().value())); |
| syncer::WriteNode::InitUniqueByCreationResult result = |
| node.InitUniqueByCreation(AUTOFILL, tag); |
| if (result != syncer::WriteNode::INIT_SUCCESS) |
| return false; |
| |
| sync_pb::EntitySpecifics specifics; |
| AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics); |
| node.SetEntitySpecifics(specifics); |
| return true; |
| } |
| |
| 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 GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries, |
| std::vector<AutofillProfile>* profiles) { |
| syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare()); |
| syncer::ReadNode autofill_root(&trans); |
| if (autofill_root.InitTypeRoot(AUTOFILL) != 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::AutofillSpecifics& autofill( |
| child_node.GetEntitySpecifics().autofill()); |
| if (autofill.has_value()) { |
| AutofillKey key(base::UTF8ToUTF16(autofill.name()), |
| base::UTF8ToUTF16(autofill.value())); |
| std::vector<Time> timestamps; |
| int timestamps_count = autofill.usage_timestamp_size(); |
| for (int i = 0; i < timestamps_count; ++i) { |
| timestamps.push_back( |
| Time::FromInternalValue(autofill.usage_timestamp(i))); |
| } |
| entries->push_back( |
| AutofillEntry(key, timestamps.front(), timestamps.back())); |
| } else if (autofill.has_profile()) { |
| AutofillProfile p; |
| p.set_guid(autofill.profile().guid()); |
| AutofillProfileSyncableService::OverwriteProfileWithServerData( |
| autofill.profile(), &p); |
| profiles->push_back(p); |
| } |
| child_id = child_node.GetSuccessorId(); |
| } |
| 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); |
| |
| // Only permit UpdateAutofillEntries() to be called with an empty list. |
| std::vector<AutofillEntry> empty; |
| EXPECT_CALL(autofill_table_, UpdateAutofillEntries(Not(empty))).Times(0); |
| } |
| |
| std::unique_ptr<syncer::DataTypeController> CreateDataTypeController( |
| syncer::ModelType type) { |
| DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE); |
| if (type == AUTOFILL) { |
| return std::make_unique<AutofillDataTypeController>( |
| data_type_thread()->task_runner(), base::Bind(&base::DoNothing), |
| sync_client_, web_data_service_); |
| } else { |
| return std::make_unique<AutofillProfileDataTypeController>( |
| data_type_thread()->task_runner(), base::Bind(&base::DoNothing), |
| sync_client_, web_data_service_); |
| } |
| } |
| |
| 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 AddAutofillHelper<AutofillEntry>; |
| friend class AddAutofillHelper<AutofillProfile>; |
| |
| base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( |
| syncer::ModelType type) { |
| DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE); |
| if (type == AUTOFILL) { |
| return AutocompleteSyncableService::FromWebDataService( |
| web_data_service_.get()) |
| ->AsWeakPtr(); |
| } else { |
| return AutofillProfileSyncableService::FromWebDataService( |
| web_data_service_.get()) |
| ->AsWeakPtr(); |
| } |
| } |
| |
| 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_; |
| // |sync_client_owned_| keeps the created client until it is passed to the |
| // created ProfileSyncService. |sync_client_| just keeps a weak reference to |
| // the client the whole time. |
| std::unique_ptr<syncer::FakeSyncClient> sync_client_owned_; |
| syncer::FakeSyncClient* sync_client_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest); |
| }; |
| |
| template <class T> |
| class AddAutofillHelper { |
| public: |
| AddAutofillHelper(ProfileSyncServiceAutofillTest* test, |
| const std::vector<T>& entries) |
| : callback_(base::Bind(&AddAutofillHelper::AddAutofillCallback, |
| base::Unretained(this), |
| test, |
| entries)), |
| success_(false) {} |
| |
| const base::Closure& callback() const { return callback_; } |
| bool success() { return success_; } |
| |
| private: |
| void AddAutofillCallback(ProfileSyncServiceAutofillTest* test, |
| const std::vector<T>& entries) { |
| if (!test->CreateRoot(GetModelType<T>())) |
| return; |
| |
| for (size_t i = 0; i < entries.size(); ++i) { |
| if (!test->AddAutofillSyncNode(entries[i])) |
| return; |
| } |
| success_ = true; |
| } |
| |
| base::Closure callback_; |
| bool success_; |
| }; |
| |
| // Overload write transaction to use custom NotifyTransactionComplete |
| class WriteTransactionTest : public WriteTransaction { |
| public: |
| WriteTransactionTest(const base::Location& from_here, |
| WriterTag writer, |
| syncer::syncable::Directory* directory, |
| WaitableEvent* wait_for_syncapi) |
| : WriteTransaction(from_here, writer, directory), |
| wait_for_syncapi_(wait_for_syncapi) {} |
| |
| void NotifyTransactionComplete(syncer::ModelTypeSet types) override { |
| // This is where we differ. Force a thread change here, giving another |
| // thread a chance to create a WriteTransaction |
| wait_for_syncapi_->Wait(); |
| |
| WriteTransaction::NotifyTransactionComplete(types); |
| } |
| |
| private: |
| WaitableEvent* const wait_for_syncapi_; |
| }; |
| |
| // Our fake server updater. Needs the RefCountedThreadSafe inheritance so we can |
| // post tasks with it. |
| class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> { |
| public: |
| FakeServerUpdater(TestProfileSyncService* service, |
| WaitableEvent* wait_for_start, |
| WaitableEvent* wait_for_syncapi, |
| scoped_refptr<base::SequencedTaskRunner> db_task_runner) |
| : entry_(MakeAutofillEntry("0", "0", 0)), |
| service_(service), |
| wait_for_start_(wait_for_start), |
| wait_for_syncapi_(wait_for_syncapi), |
| is_finished_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| base::WaitableEvent::InitialState::NOT_SIGNALED), |
| db_task_runner_(db_task_runner) {} |
| |
| void Update() { |
| // This gets called in a modelsafeworker thread. |
| ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence()); |
| |
| syncer::UserShare* user_share = service_->GetUserShare(); |
| syncer::syncable::Directory* directory = user_share->directory.get(); |
| |
| // Create autofill protobuf. |
| std::string tag = AutocompleteSyncableService::KeyToTag( |
| base::UTF16ToUTF8(entry_.key().name()), |
| base::UTF16ToUTF8(entry_.key().value())); |
| sync_pb::AutofillSpecifics new_autofill; |
| new_autofill.set_name(base::UTF16ToUTF8(entry_.key().name())); |
| new_autofill.set_value(base::UTF16ToUTF8(entry_.key().value())); |
| new_autofill.add_usage_timestamp(entry_.date_created().ToInternalValue()); |
| if (entry_.date_created() != entry_.date_last_used()) { |
| new_autofill.add_usage_timestamp( |
| entry_.date_last_used().ToInternalValue()); |
| } |
| |
| sync_pb::EntitySpecifics entity_specifics; |
| entity_specifics.mutable_autofill()->CopyFrom(new_autofill); |
| |
| { |
| // Tell main thread we've started |
| wait_for_start_->Signal(); |
| |
| // Create write transaction. |
| WriteTransactionTest trans(FROM_HERE, UNITTEST, directory, |
| wait_for_syncapi_); |
| |
| // Create actual entry based on autofill protobuf information. |
| // Simulates effects of UpdateLocalDataFromServerData |
| MutableEntry parent(&trans, GET_TYPE_ROOT, AUTOFILL); |
| MutableEntry item(&trans, CREATE, AUTOFILL, parent.GetId(), tag); |
| ASSERT_TRUE(item.good()); |
| item.PutSpecifics(entity_specifics); |
| item.PutServerSpecifics(entity_specifics); |
| item.PutBaseVersion(1); |
| syncer::syncable::Id server_item_id = |
| service_->id_factory()->NewServerId(); |
| item.PutId(server_item_id); |
| syncer::syncable::Id new_predecessor; |
| ASSERT_TRUE(item.PutPredecessor(new_predecessor)); |
| } |
| DVLOG(1) << "FakeServerUpdater finishing."; |
| is_finished_.Signal(); |
| } |
| |
| void CreateNewEntry(const AutofillEntry& entry) { |
| entry_ = entry; |
| ASSERT_FALSE(db_task_runner_->RunsTasksInCurrentSequence()); |
| if (!db_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&FakeServerUpdater::Update, this))) { |
| NOTREACHED() << "Failed to post task to the db sequence."; |
| return; |
| } |
| } |
| |
| void WaitForUpdateCompletion() { is_finished_.Wait(); } |
| |
| private: |
| friend class base::RefCountedThreadSafe<FakeServerUpdater>; |
| ~FakeServerUpdater() {} |
| |
| AutofillEntry entry_; |
| TestProfileSyncService* service_; |
| WaitableEvent* const wait_for_start_; |
| WaitableEvent* const wait_for_syncapi_; |
| WaitableEvent is_finished_; |
| syncer::syncable::Id parent_id_; |
| scoped_refptr<base::SequencedTaskRunner> db_task_runner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FakeServerUpdater); |
| }; |
| |
| // TODO(skrul): Test abort startup. |
| // TODO(skrul): Test processing of cloud changes. |
| // TODO(tim): Add autofill data type controller test, and a case to cover |
| // waiting for the PersonalDataManager. |
| TEST_F(ProfileSyncServiceAutofillTest, FailModelAssociation) { |
| // Don't create the root autofill node so startup fails. |
| StartSyncService(base::Closure(), true, AUTOFILL); |
| EXPECT_TRUE(sync_service()->HasUnrecoverableError()); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) { |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(Return(true)); |
| SetIdleChangeProcessorExpectations(); |
| CreateRootHelper create_root(this, AUTOFILL); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| EXPECT_TRUE(create_root.success()); |
| std::vector<AutofillEntry> sync_entries; |
| std::vector<AutofillProfile> sync_profiles; |
| ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles)); |
| EXPECT_EQ(0U, sync_entries.size()); |
| EXPECT_EQ(0U, sync_profiles.size()); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, HasNativeEntriesEmptySync) { |
| std::vector<AutofillEntry> entries; |
| entries.push_back(MakeAutofillEntry("foo", "bar", 1)); |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(entries), Return(true))); |
| SetIdleChangeProcessorExpectations(); |
| CreateRootHelper create_root(this, AUTOFILL); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| std::vector<AutofillEntry> sync_entries; |
| std::vector<AutofillProfile> sync_profiles; |
| ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles)); |
| ASSERT_EQ(1U, sync_entries.size()); |
| EXPECT_EQ(entries[0], sync_entries[0]); |
| EXPECT_EQ(0U, sync_profiles.size()); |
| } |
| |
| 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); |
| StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE); |
| 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, HasNativeWithDuplicatesEmptySync) { |
| // There is buggy autofill code that allows duplicate name/value |
| // pairs to exist in the database with separate pair_ids. |
| std::vector<AutofillEntry> entries; |
| entries.push_back(MakeAutofillEntry("foo", "bar", 1)); |
| entries.push_back(MakeAutofillEntry("dup", "", 2)); |
| entries.push_back(MakeAutofillEntry("dup", "", 3)); |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(entries), Return(true))); |
| SetIdleChangeProcessorExpectations(); |
| CreateRootHelper create_root(this, AUTOFILL); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| std::vector<AutofillEntry> sync_entries; |
| std::vector<AutofillProfile> sync_profiles; |
| ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles)); |
| EXPECT_EQ(2U, sync_entries.size()); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge) { |
| AutofillEntry native_entry(MakeAutofillEntry("native", "entry", 1)); |
| AutofillEntry sync_entry(MakeAutofillEntry("sync", "entry", 2)); |
| |
| std::vector<AutofillEntry> native_entries; |
| native_entries.push_back(native_entry); |
| |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true))); |
| |
| std::vector<AutofillEntry> sync_entries; |
| sync_entries.push_back(sync_entry); |
| |
| AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries); |
| |
| EXPECT_CALL(autofill_table(), UpdateAutofillEntries(ElementsAre(sync_entry))) |
| .WillOnce(Return(true)); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL); |
| ASSERT_TRUE(add_autofill.success()); |
| |
| std::set<AutofillEntry> expected_entries; |
| expected_entries.insert(native_entry); |
| expected_entries.insert(sync_entry); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(), |
| new_sync_entries.end()); |
| |
| EXPECT_EQ(expected_entries, new_sync_entries_set); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge_NullTerminated) { |
| const char kEntry[] = "entry"; |
| // A value which contains null terminating symbol. |
| std::string entry(kEntry, arraysize(kEntry)); |
| AutofillEntry native_entry0(MakeAutofillEntry("native", kEntry, 1)); |
| AutofillEntry native_entry1(MakeAutofillEntry("native", entry, 1)); |
| AutofillEntry sync_entry0(MakeAutofillEntry("sync", kEntry, 2)); |
| AutofillEntry sync_entry1(MakeAutofillEntry("sync", entry, 2)); |
| |
| std::vector<AutofillEntry> native_entries; |
| native_entries.push_back(native_entry0); |
| native_entries.push_back(native_entry1); |
| |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true))); |
| |
| std::vector<AutofillEntry> sync_entries; |
| sync_entries.push_back(sync_entry0); |
| sync_entries.push_back(sync_entry1); |
| |
| AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries); |
| |
| // Expecting that sync_entry0 and sync_entry1 will be written in an autofill |
| // table and a value in sync_entry1 won't lose null terminating symbol. |
| EXPECT_CALL(autofill_table(), |
| UpdateAutofillEntries(ElementsAre(sync_entry0, sync_entry1))) |
| .WillOnce(Return(true)); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL); |
| ASSERT_TRUE(add_autofill.success()); |
| |
| // Expecting that native_entry0 and native_entry1 won't merge into one entry. |
| std::set<AutofillEntry> expected_entries; |
| expected_entries.insert(native_entry0); |
| expected_entries.insert(native_entry1); |
| expected_entries.insert(sync_entry0); |
| expected_entries.insert(sync_entry1); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(), |
| new_sync_entries.end()); |
| |
| EXPECT_EQ(expected_entries, new_sync_entries_set); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeEntry) { |
| AutofillEntry native_entry(MakeAutofillEntry("merge", "entry", 1)); |
| AutofillEntry sync_entry(MakeAutofillEntry("merge", "entry", 2)); |
| AutofillEntry merged_entry(MakeAutofillEntry("merge", "entry", 1, 2)); |
| |
| std::vector<AutofillEntry> native_entries; |
| native_entries.push_back(native_entry); |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true))); |
| |
| std::vector<AutofillEntry> sync_entries; |
| sync_entries.push_back(sync_entry); |
| AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries); |
| |
| EXPECT_CALL(autofill_table(), |
| UpdateAutofillEntries(ElementsAre(merged_entry))) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL); |
| ASSERT_TRUE(add_autofill.success()); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| ASSERT_EQ(1U, new_sync_entries.size()); |
| EXPECT_EQ(merged_entry, new_sync_entries[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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| |
| EXPECT_CALL(autofill_table(), |
| UpdateAutofillProfile(MatchProfiles(sync_profile))) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| // Adds all entries in |sync_profiles| to sync. |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| // Adds all entries in |sync_profiles| to sync. |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| // Adds all entries in |sync_profiles| to sync. |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| // Adds all entries in |sync_profiles| to sync. |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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); |
| AddAutofillHelper<AutofillProfile> 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()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| 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, ProcessUserChangeAddEntry) { |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| SetIdleChangeProcessorExpectations(); |
| CreateRootHelper create_root(this, AUTOFILL); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| |
| AutofillEntry added_entry(MakeAutofillEntry("added", "entry", 1)); |
| |
| EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(added_entry.date_created()), |
| SetArgPointee<3>(added_entry.date_last_used()), |
| Return(true))); |
| |
| AutofillChangeList changes; |
| changes.push_back(AutofillChange(AutofillChange::ADD, added_entry.key())); |
| |
| web_data_service()->OnAutofillEntriesChanged(changes); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| ASSERT_EQ(1U, new_sync_entries.size()); |
| EXPECT_EQ(added_entry, new_sync_entries[0]); |
| } |
| |
| 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); |
| StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE); |
| 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"); |
| |
| 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, ProcessUserChangeUpdateEntry) { |
| AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1)); |
| std::vector<AutofillEntry> original_entries; |
| original_entries.push_back(original_entry); |
| |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(original_entries), Return(true))); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| CreateRootHelper create_root(this, AUTOFILL); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| |
| AutofillEntry updated_entry(MakeAutofillEntry("my", "entry", 1, 2)); |
| |
| EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(updated_entry.date_created()), |
| SetArgPointee<3>(updated_entry.date_last_used()), |
| Return(true))); |
| |
| AutofillChangeList changes; |
| changes.push_back( |
| AutofillChange(AutofillChange::UPDATE, updated_entry.key())); |
| web_data_service()->OnAutofillEntriesChanged(changes); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| ASSERT_EQ(1U, new_sync_entries.size()); |
| EXPECT_EQ(updated_entry, new_sync_entries[0]); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveEntry) { |
| AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1)); |
| std::vector<AutofillEntry> original_entries; |
| original_entries.push_back(original_entry); |
| |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(original_entries), Return(true))); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| CreateRootHelper create_root(this, AUTOFILL); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| |
| AutofillChangeList changes; |
| changes.push_back( |
| AutofillChange(AutofillChange::REMOVE, original_entry.key())); |
| web_data_service()->OnAutofillEntriesChanged(changes); |
| |
| std::vector<AutofillEntry> new_sync_entries; |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles)); |
| ASSERT_EQ(0U, new_sync_entries.size()); |
| } |
| |
| 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); |
| AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles); |
| EXPECT_CALL(personal_data_manager(), Refresh()); |
| StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE); |
| ASSERT_TRUE(add_autofill.success()); |
| |
| AutofillProfileChange change(AutofillProfileChange::REMOVE, |
| sync_profile.guid(), nullptr); |
| web_data_service()->OnAutofillProfileChanged(change); |
| |
| std::vector<AutofillProfile> new_sync_profiles; |
| ASSERT_TRUE( |
| GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles)); |
| ASSERT_EQ(0U, new_sync_profiles.size()); |
| } |
| |
| TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) { |
| // Once for MergeDataAndStartSyncing() and twice for ProcessSyncChanges(), via |
| // LoadAutofillData(). |
| EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_)) |
| .Times(3) |
| .WillRepeatedly(Return(true)); |
| // On the other hand Autofill and Autocomplete are separated now, so |
| // GetAutofillProfiles() should not be called. |
| EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).Times(0); |
| EXPECT_CALL(autofill_table(), UpdateAutofillEntries(_)) |
| .WillRepeatedly(Return(true)); |
| EXPECT_CALL(personal_data_manager(), Refresh()).Times(3); |
| CreateRootHelper create_root(this, AUTOFILL); |
| StartSyncService(create_root.callback(), false, AUTOFILL); |
| ASSERT_TRUE(create_root.success()); |
| |
| std::unique_ptr<WaitableEvent> wait_for_start( |
| new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED)); |
| std::unique_ptr<WaitableEvent> wait_for_syncapi( |
| new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED)); |
| scoped_refptr<FakeServerUpdater> updater(new FakeServerUpdater( |
| sync_service(), wait_for_start.get(), wait_for_syncapi.get(), |
| data_type_thread()->task_runner())); |
| |
| // This server side update will stall waiting for CommitWaiter. |
| updater->CreateNewEntry(MakeAutofillEntry("server", "entry", 1)); |
| wait_for_start->Wait(); |
| |
| AutofillEntry syncapi_entry(MakeAutofillEntry("syncapi", "entry", 2)); |
| ASSERT_TRUE(AddAutofillSyncNode(syncapi_entry)); |
| DVLOG(1) << "Syncapi update finished."; |
| |
| // If we reach here, it means syncapi succeeded and we didn't deadlock. Yay! |
| // Signal FakeServerUpdater that it can complete. |
| wait_for_syncapi->Signal(); |
| |
| // Make another entry to ensure nothing broke afterwards and wait for finish |
| // to clean up. |
| updater->WaitForUpdateCompletion(); |
| updater->CreateNewEntry(MakeAutofillEntry("server2", "entry2", 3)); |
| updater->WaitForUpdateCompletion(); |
| |
| // Let callbacks posted on UI sequence execute. |
| base::RunLoop().RunUntilIdle(); |
| |
| std::vector<AutofillEntry> sync_entries; |
| std::vector<AutofillProfile> sync_profiles; |
| ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles)); |
| EXPECT_EQ(3U, sync_entries.size()); |
| EXPECT_EQ(0U, sync_profiles.size()); |
| for (size_t i = 0; i < sync_entries.size(); i++) { |
| DVLOG(1) << "Entry " << i << ": " << sync_entries[i].key().name() << ", " |
| << sync_entries[i].key().value(); |
| } |
| } |
| |
| } // namespace browser_sync |