// 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 #include #include #include "testing/gtest/include/gtest/gtest.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" #include "base/compiler_specific.h" #include "base/location.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/time/time.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/signin/signin_manager.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/token_service_factory.h" #include "chrome/browser/sync/abstract_profile_sync_service_test.h" #include "chrome/browser/sync/fake_oauth2_token_service.h" #include "chrome/browser/sync/glue/autofill_data_type_controller.h" #include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h" #include "chrome/browser/sync/glue/data_type_controller.h" #include "chrome/browser/sync/glue/generic_change_processor.h" #include "chrome/browser/sync/glue/shared_change_processor.h" #include "chrome/browser/sync/profile_sync_components_factory.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_test_util.h" #include "chrome/browser/sync/test_profile_sync_service.h" #include "chrome/browser/webdata/autocomplete_syncable_service.h" #include "chrome/browser/webdata/autofill_profile_syncable_service.h" #include "chrome/browser/webdata/web_data_service_factory.h" #include "components/autofill/core/browser/autofill_test_utils.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_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/webdata/common/web_data_service_test_util.h" #include "components/webdata/common/web_database.h" #include "content/public/test/test_browser_thread.h" #include "google_apis/gaia/gaia_constants.h" #include "sync/internal_api/public/base/model_type.h" #include "sync/internal_api/public/data_type_debug_info_listener.h" #include "sync/internal_api/public/read_node.h" #include "sync/internal_api/public/read_transaction.h" #include "sync/internal_api/public/write_node.h" #include "sync/internal_api/public/write_transaction.h" #include "sync/protocol/autofill_specifics.pb.h" #include "sync/syncable/mutable_entry.h" #include "sync/syncable/syncable_write_transaction.h" #include "sync/test/engine/test_id_factory.h" #include "testing/gmock/include/gmock/gmock.h" using autofill::AutofillChange; using autofill::AutofillChangeList; using autofill::AutofillEntry; using autofill::ServerFieldType; using autofill::AutofillKey; using autofill::AutofillProfile; using autofill::AutofillProfileChange; using autofill::AutofillTable; using autofill::AutofillWebDataService; using autofill::PersonalDataManager; using base::Time; using base::TimeDelta; using base::WaitableEvent; using browser_sync::AutofillDataTypeController; using browser_sync::AutofillProfileDataTypeController; using browser_sync::DataTypeController; using browser_sync::GenericChangeProcessor; using browser_sync::SharedChangeProcessor; using content::BrowserThread; using syncer::AUTOFILL; using syncer::BaseNode; using syncer::syncable::BASE_VERSION; using syncer::syncable::CREATE; using syncer::syncable::GET_BY_SERVER_TAG; using syncer::syncable::MutableEntry; using syncer::syncable::SERVER_SPECIFICS; using syncer::syncable::SPECIFICS; using syncer::syncable::UNITTEST; using syncer::syncable::WriterTag; using syncer::syncable::WriteTransaction; using testing::_; using testing::DoAll; using testing::ElementsAre; using testing::SetArgumentPointee; using testing::Return; class HistoryService; namespace syncable { class Id; } namespace { void RunAndSignal(const base::Closure& cb, WaitableEvent* event) { cb.Run(); event->Signal(); } } // namespace class AutofillTableMock : public AutofillTable { public: AutofillTableMock() : AutofillTable("en-US") {} MOCK_METHOD2(RemoveFormElement, bool(const string16& name, const string16& value)); // NOLINT MOCK_METHOD1(GetAllAutofillEntries, bool(std::vector* entries)); // NOLINT MOCK_METHOD3(GetAutofillTimestamps, bool(const string16& name, // NOLINT const string16& value, std::vector* timestamps)); MOCK_METHOD1(UpdateAutofillEntries, bool(const std::vector&)); // NOLINT MOCK_METHOD1(GetAutofillProfiles, bool(std::vector*)); // 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); } 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) : web_database_(web_database), on_changed_(on_changed) { } virtual ~MockAutofillBackend() {} virtual WebDatabase* GetDatabase() OVERRIDE { return web_database_; } virtual void AddObserver( autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {} virtual void RemoveObserver( autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {} virtual void RemoveExpiredFormElements() OVERRIDE {} virtual void NotifyOfMultipleAutofillChanges() OVERRIDE { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, on_changed_); } private: WebDatabase* web_database_; base::Closure on_changed_; }; class ProfileSyncServiceAutofillTest; template syncer::ModelType GetModelType() { return syncer::UNSPECIFIED; } template<> syncer::ModelType GetModelType() { return syncer::AUTOFILL; } template<> syncer::ModelType GetModelType() { return syncer::AUTOFILL_PROFILE; } class TokenWebDataServiceFake : public TokenWebData { public: TokenWebDataServiceFake() : TokenWebData() { } virtual bool IsDatabaseLoaded() OVERRIDE { return true; } virtual WebDataService::Handle GetAllTokens( WebDataServiceConsumer* consumer) OVERRIDE { // TODO(tim): It would be nice if WebDataService was injected on // construction of TokenService 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: virtual ~TokenWebDataServiceFake() {} DISALLOW_COPY_AND_ASSIGN(TokenWebDataServiceFake); }; class WebDataServiceFake : public AutofillWebDataService { public: WebDataServiceFake() : AutofillWebDataService( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)), web_database_(NULL), autocomplete_syncable_service_(NULL), autofill_profile_syncable_service_(NULL), syncable_service_created_or_destroyed_(false, false) { } void SetDatabase(WebDatabase* web_database) { web_database_ = web_database; } void StartSyncableService() { // The |autofill_profile_syncable_service_| must be constructed on the DB // thread. const base::Closure& on_changed_callback = base::Bind( &WebDataServiceFake::NotifyAutofillMultipleChangedOnUIThread, AsWeakPtr()); BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(&WebDataServiceFake::CreateSyncableService, base::Unretained(this), on_changed_callback)); syncable_service_created_or_destroyed_.Wait(); } void ShutdownSyncableService() { // The |autofill_profile_syncable_service_| must be destructed on the DB // thread. BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(&WebDataServiceFake::DestroySyncableService, base::Unretained(this))); syncable_service_created_or_destroyed_.Wait(); } virtual bool IsDatabaseLoaded() OVERRIDE { return true; } virtual WebDatabase* GetDatabase() OVERRIDE { return web_database_; } void OnAutofillEntriesChanged(const AutofillChangeList& changes) { WaitableEvent event(true, false); base::Closure notify_cb = base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged, base::Unretained(autocomplete_syncable_service_), changes); BrowserThread::PostTask( BrowserThread::DB, FROM_HERE, base::Bind(&RunAndSignal, notify_cb, &event)); event.Wait(); } void OnAutofillProfileChanged(const AutofillProfileChange& changes) { WaitableEvent event(true, false); base::Closure notify_cb = base::Bind(&AutocompleteSyncableService::AutofillProfileChanged, base::Unretained(autofill_profile_syncable_service_), changes); BrowserThread::PostTask( BrowserThread::DB, FROM_HERE, base::Bind(&RunAndSignal, notify_cb, &event)); event.Wait(); } private: virtual ~WebDataServiceFake() {} void CreateSyncableService(const base::Closure& on_changed_callback) { ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB)); // These services are deleted in DestroySyncableService(). backend_.reset(new MockAutofillBackend( GetDatabase(), on_changed_callback)); 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(BrowserThread::CurrentlyOn(BrowserThread::DB)); autocomplete_syncable_service_ = NULL; autofill_profile_syncable_service_ = NULL; backend_.reset(); syncable_service_created_or_destroyed_.Signal(); } WebDatabase* web_database_; AutocompleteSyncableService* autocomplete_syncable_service_; AutofillProfileSyncableService* autofill_profile_syncable_service_; scoped_ptr backend_; WaitableEvent syncable_service_created_or_destroyed_; DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake); }; BrowserContextKeyedService* BuildMockWebDataServiceWrapper( content::BrowserContext* profile) { return new MockWebDataServiceWrapper( NULL, new WebDataServiceFake(), new TokenWebDataServiceFake()); } ACTION_P(MakeAutocompleteSyncComponents, wds) { EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB)); if (!BrowserThread::CurrentlyOn(BrowserThread::DB)) return base::WeakPtr(); return AutocompleteSyncableService::FromWebDataService(wds)->AsWeakPtr(); } ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) { return new browser_sync::DataTypeManagerImpl( debug_listener, arg1, arg2, arg3, arg4, arg5); } ACTION(MakeGenericChangeProcessor) { syncer::UserShare* user_share = arg0->GetUserShare(); return new GenericChangeProcessor( arg1, arg2, arg3, user_share); } ACTION(MakeSharedChangeProcessor) { return new SharedChangeProcessor(); } ACTION_P(MakeAutofillProfileSyncComponents, wds) { EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB)); if (!BrowserThread::CurrentlyOn(BrowserThread::DB)) return base::WeakPtr(); return AutofillProfileSyncableService::FromWebDataService(wds)->AsWeakPtr(); } class AbstractAutofillFactory { public: virtual DataTypeController* CreateDataTypeController( ProfileSyncComponentsFactory* factory, TestingProfile* profile, ProfileSyncService* service) = 0; virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory, ProfileSyncService* service, AutofillWebDataService* wds, DataTypeController* dtc) = 0; virtual ~AbstractAutofillFactory() {} }; class AutofillEntryFactory : public AbstractAutofillFactory { public: virtual browser_sync::DataTypeController* CreateDataTypeController( ProfileSyncComponentsFactory* factory, TestingProfile* profile, ProfileSyncService* service) OVERRIDE { return new AutofillDataTypeController(factory, profile, service); } virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory, ProfileSyncService* service, AutofillWebDataService* wds, DataTypeController* dtc) OVERRIDE { EXPECT_CALL(*factory, CreateGenericChangeProcessor(_,_,_,_)). WillOnce(MakeGenericChangeProcessor()); EXPECT_CALL(*factory, CreateSharedChangeProcessor()). WillOnce(MakeSharedChangeProcessor()); EXPECT_CALL(*factory, GetSyncableServiceForType(syncer::AUTOFILL)). WillOnce(MakeAutocompleteSyncComponents(wds)); } }; class AutofillProfileFactory : public AbstractAutofillFactory { public: virtual browser_sync::DataTypeController* CreateDataTypeController( ProfileSyncComponentsFactory* factory, TestingProfile* profile, ProfileSyncService* service) OVERRIDE { return new AutofillProfileDataTypeController(factory, profile, service); } virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory, ProfileSyncService* service, AutofillWebDataService* wds, DataTypeController* dtc) OVERRIDE { EXPECT_CALL(*factory, CreateGenericChangeProcessor(_,_,_,_)). WillOnce(MakeGenericChangeProcessor()); EXPECT_CALL(*factory, CreateSharedChangeProcessor()). WillOnce(MakeSharedChangeProcessor()); EXPECT_CALL(*factory, GetSyncableServiceForType(syncer::AUTOFILL_PROFILE)). WillOnce(MakeAutofillProfileSyncComponents(wds)); } }; 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()); }; class MockPersonalDataManagerService : public autofill::PersonalDataManagerService { public: static BrowserContextKeyedService* Build(content::BrowserContext* profile) { return new MockPersonalDataManagerService(); } MockPersonalDataManagerService() { personal_data_manager_.reset(new MockPersonalDataManager()); } virtual ~MockPersonalDataManagerService() {} virtual void Shutdown() OVERRIDE { personal_data_manager_.reset(); } virtual MockPersonalDataManager* GetPersonalDataManager() OVERRIDE { return personal_data_manager_.get(); } private: scoped_ptr personal_data_manager_; DISALLOW_COPY_AND_ASSIGN(MockPersonalDataManagerService); }; template class AddAutofillHelper; class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest, public syncer::DataTypeDebugInfoListener { public: // DataTypeDebugInfoListener implementation. virtual void OnDataTypeConfigureComplete( const std::vector& configuration_stats) OVERRIDE { ASSERT_EQ(1u, configuration_stats.size()); association_stats_ = configuration_stats[0].association_stats; } protected: ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) { } virtual ~ProfileSyncServiceAutofillTest() { } AutofillProfileFactory profile_factory_; AutofillEntryFactory entry_factory_; AbstractAutofillFactory* GetFactory(syncer::ModelType type) { if (type == syncer::AUTOFILL) { return &entry_factory_; } else if (type == syncer::AUTOFILL_PROFILE) { return &profile_factory_; } else { NOTREACHED(); return NULL; } } virtual void SetUp() OVERRIDE { AbstractProfileSyncServiceTest::SetUp(); TestingProfile::Builder builder; builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), FakeOAuth2TokenService::BuildTokenService); profile_ = builder.Build().Pass(); web_database_.reset(new WebDatabaseFake(&autofill_table_)); MockWebDataServiceWrapper* wrapper = static_cast( WebDataServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile_.get(), BuildMockWebDataServiceWrapper)); web_data_service_ = static_cast(wrapper->GetAutofillWebData().get()); web_data_service_->SetDatabase(web_database_.get()); MockPersonalDataManagerService* personal_data_manager_service = static_cast( autofill::PersonalDataManagerFactory::GetInstance() ->SetTestingFactoryAndUse( profile_.get(), MockPersonalDataManagerService::Build)); personal_data_manager_ = personal_data_manager_service->GetPersonalDataManager(); token_service_ = static_cast( TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile_.get(), BuildTokenService)); EXPECT_CALL(*personal_data_manager_, LoadProfiles()).Times(1); EXPECT_CALL(*personal_data_manager_, LoadCreditCards()).Times(1); personal_data_manager_->Init(profile_.get(), profile_->GetPrefs(), profile_->IsOffTheRecord()); web_data_service_->StartSyncableService(); } virtual void TearDown() OVERRIDE { // Note: The tear down order is important. ProfileSyncServiceFactory::GetInstance()->SetTestingFactory( profile_.get(), NULL); web_data_service_->ShutdownOnUIThread(); web_data_service_->ShutdownSyncableService(); web_data_service_ = NULL; // To prevent a leak, fully release TestURLRequestContext to ensure its // destruction on the IO message loop. profile_.reset(); AbstractProfileSyncServiceTest::TearDown(); } int GetSyncCount(syncer::ModelType type) { syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); syncer::ReadNode node(&trans); if (node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) != syncer::BaseNode::INIT_OK) return 0; return node.GetTotalNodeCount() - 1; } void StartSyncService(const base::Closure& callback, bool will_fail_association, syncer::ModelType type) { AbstractAutofillFactory* factory = GetFactory(type); SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_.get()); signin->SetAuthenticatedUsername("test_user@gmail.com"); sync_service_ = static_cast( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile_.get(), &TestProfileSyncService::BuildAutoStartAsyncInit)); sync_service_->set_backend_init_callback(callback); ProfileSyncComponentsFactoryMock* components = sync_service_->components_factory_mock(); DataTypeController* data_type_controller = factory->CreateDataTypeController(components, profile_.get(), sync_service_); factory->SetExpectation(components, sync_service_, web_data_service_.get(), data_type_controller); EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _, _)). WillOnce(ReturnNewDataTypeManagerWithDebugListener( syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr()))); EXPECT_CALL(*personal_data_manager_, IsDataLoaded()). WillRepeatedly(Return(true)); // We need tokens to get the tests going ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get()) ->UpdateCredentials("test_user@gmail.com", "oauth2_login_token"); sync_service_->RegisterDataTypeController(data_type_controller); sync_service_->Initialize(); base::MessageLoop::current()->Run(); // It's possible this test triggered an unrecoverable error, in which case // we can't get the sync count. if (sync_service_->ShouldPushChanges()) { 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::ReadNode autofill_root(&trans); if (autofill_root.InitByTagLookup( syncer::ModelTypeToRootTag(syncer::AUTOFILL)) != BaseNode::INIT_OK) { return false; } syncer::WriteNode node(&trans); std::string tag = AutocompleteSyncableService::KeyToTag( UTF16ToUTF8(entry.key().name()), UTF16ToUTF8(entry.key().value())); syncer::WriteNode::InitUniqueByCreationResult result = node.InitUniqueByCreation(syncer::AUTOFILL, autofill_root, tag); if (result != syncer::WriteNode::INIT_SUCCESS) return false; sync_pb::EntitySpecifics specifics; AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics); sync_pb::AutofillSpecifics* autofill_specifics = specifics.mutable_autofill(); node.SetAutofillSpecifics(*autofill_specifics); return true; } bool AddAutofillSyncNode(const AutofillProfile& profile) { syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); syncer::ReadNode autofill_root(&trans); if (autofill_root.InitByTagLookup(kAutofillProfileTag) != BaseNode::INIT_OK) { return false; } syncer::WriteNode node(&trans); std::string tag = profile.guid(); syncer::WriteNode::InitUniqueByCreationResult result = node.InitUniqueByCreation(syncer::AUTOFILL_PROFILE, autofill_root, tag); if (result != syncer::WriteNode::INIT_SUCCESS) return false; sync_pb::EntitySpecifics specifics; AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics); sync_pb::AutofillProfileSpecifics* profile_specifics = specifics.mutable_autofill_profile(); node.SetAutofillProfileSpecifics(*profile_specifics); return true; } bool GetAutofillEntriesFromSyncDB(std::vector* entries, std::vector* profiles) { syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); syncer::ReadNode autofill_root(&trans); if (autofill_root.InitByTagLookup( syncer::ModelTypeToRootTag(syncer::AUTOFILL)) != BaseNode::INIT_OK) { return false; } int64 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.GetAutofillSpecifics()); if (autofill.has_value()) { AutofillKey key(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value())); std::vector 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)); } else if (autofill.has_profile()) { AutofillProfile p; p.set_guid(autofill.profile().guid()); AutofillProfileSyncableService::OverwriteProfileWithServerData( autofill.profile(), &p, "en-US"); profiles->push_back(p); } child_id = child_node.GetSuccessorId(); } return true; } bool GetAutofillProfilesFromSyncDBUnderProfileNode( std::vector* profiles) { syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); syncer::ReadNode autofill_root(&trans); if (autofill_root.InitByTagLookup(kAutofillProfileTag) != BaseNode::INIT_OK) { return false; } int64 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.GetAutofillProfileSpecifics()); AutofillProfile p; p.set_guid(autofill.guid()); AutofillProfileSyncableService::OverwriteProfileWithServerData( autofill, &p, "en-US"); 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); EXPECT_CALL(autofill_table_, UpdateAutofillEntries(_)).Times(0); } static AutofillEntry MakeAutofillEntry(const char* name, const char* 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(); std::vector