普通文本  |  1099行  |  43.09 KB

// Copyright (c) 2011 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 <set>
#include <string>
#include <vector>

#include "testing/gtest/include/gtest/gtest.h"

#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/string16.h"
#include "base/synchronization/waitable_event.h"
#include "base/task.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_test.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/engine/model_changing_syncer_command.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/syncable/autofill_migration.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/autofill_table.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/test/profile_mock.h"
#include "chrome/test/sync/engine/test_id_factory.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
#include "testing/gmock/include/gmock/gmock.h"

using base::Time;
using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::AutofillProfileChangeProcessor;
using browser_sync::AutofillProfileDataTypeController;
using browser_sync::AutofillProfileModelAssociator;
using browser_sync::DataTypeController;
using browser_sync::GROUP_DB;
using browser_sync::kAutofillTag;
using browser_sync::SyncBackendHostForProfileSyncTest;
using browser_sync::UnrecoverableErrorHandler;
using syncable::CREATE_NEW_UPDATE_ITEM;
using syncable::AUTOFILL;
using syncable::BASE_VERSION;
using syncable::CREATE;
using syncable::GET_BY_SERVER_TAG;
using syncable::INVALID;
using syncable::MutableEntry;
using syncable::OriginalEntries;
using syncable::SERVER_PARENT_ID;
using syncable::SERVER_SPECIFICS;
using syncable::SPECIFICS;
using syncable::UNITTEST;
using syncable::WriterTag;
using syncable::WriteTransaction;
using testing::_;
using testing::DoAll;
using testing::DoDefault;
using testing::ElementsAre;
using testing::Eq;
using testing::Invoke;
using testing::Mock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgumentPointee;

namespace syncable {
class Id;
}

class AutofillTableMock : public AutofillTable {
 public:
  AutofillTableMock() : AutofillTable(NULL, NULL) {}
  MOCK_METHOD2(RemoveFormElement,
               bool(const string16& name, const string16& value));  // NOLINT
  MOCK_METHOD1(GetAllAutofillEntries,
               bool(std::vector<AutofillEntry>* entries));  // NOLINT
  MOCK_METHOD3(GetAutofillTimestamps,
               bool(const string16& name,  // NOLINT
                    const string16& value,
                    std::vector<base::Time>* timestamps));
  MOCK_METHOD1(UpdateAutofillEntries,
               bool(const std::vector<AutofillEntry>&));  // NOLINT
  MOCK_METHOD1(GetAutofillProfiles,
               bool(std::vector<AutofillProfile*>*));  // NOLINT
  MOCK_METHOD1(UpdateAutofillProfile,
               bool(const AutofillProfile&));  // NOLINT
  MOCK_METHOD1(AddAutofillProfile,
               bool(const AutofillProfile&));  // NOLINT
  MOCK_METHOD1(RemoveAutofillProfile,
               bool(const std::string&));  // NOLINT
};

class WebDatabaseFake : public WebDatabase {
 public:
  explicit WebDatabaseFake(AutofillTable* autofill_table)
      : autofill_table_(autofill_table) {}

  virtual AutofillTable* GetAutofillTable() {
    return autofill_table_;
  }

 private:
  AutofillTable* autofill_table_;
};


class ProfileSyncServiceAutofillTest;

template<class AutofillProfile>
syncable::ModelType GetModelType() {
  return syncable::UNSPECIFIED;
}

template<>
syncable::ModelType GetModelType<AutofillEntry>() {
  return syncable::AUTOFILL;
}

template<>
syncable::ModelType GetModelType<AutofillProfile>() {
  return syncable::AUTOFILL_PROFILE;
}

class WebDataServiceFake : public WebDataService {
 public:
  explicit WebDataServiceFake(WebDatabase* web_database)
      : web_database_(web_database) {}
  virtual bool IsDatabaseLoaded() {
    return true;
  }

  virtual WebDatabase* GetDatabase() {
    return web_database_;
  }

 private:
  WebDatabase* web_database_;
};

ACTION_P4(MakeAutofillSyncComponents, service, wd, pdm, dtc) {
  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));
  if (!BrowserThread::CurrentlyOn(BrowserThread::DB))
    return ProfileSyncFactory::SyncComponents(NULL, NULL);
  AutofillModelAssociator* model_associator =
      new AutofillModelAssociator(service, wd, pdm);
  AutofillChangeProcessor* change_processor =
      new AutofillChangeProcessor(model_associator, wd, pdm, dtc);
  return ProfileSyncFactory::SyncComponents(model_associator,
                                            change_processor);
}

ACTION_P4(MakeAutofillProfileSyncComponents, service, wd, pdm, dtc) {
  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));
  if (!BrowserThread::CurrentlyOn(BrowserThread::DB))
    return ProfileSyncFactory::SyncComponents(NULL, NULL);
  AutofillProfileModelAssociator* model_associator =
      new AutofillProfileModelAssociator(service, wd, pdm);
  AutofillProfileChangeProcessor* change_processor =
      new AutofillProfileChangeProcessor(model_associator, wd, pdm, dtc);
  return ProfileSyncFactory::SyncComponents(model_associator,
                                            change_processor);
}

class AbstractAutofillFactory {
 public:
  virtual AutofillDataTypeController* CreateDataTypeController(
    ProfileSyncFactory *factory,
      ProfileMock* profile,
      ProfileSyncService* service) = 0;
  virtual void SetExpectation(ProfileSyncFactoryMock* factory,
      ProfileSyncService* service,
      WebDatabase* wd,
      PersonalDataManager* pdm,
      DataTypeController* dtc) = 0;
  virtual ~AbstractAutofillFactory() {}
};

class AutofillEntryFactory : public AbstractAutofillFactory {
 public:
  browser_sync::AutofillDataTypeController* CreateDataTypeController(
      ProfileSyncFactory *factory,
      ProfileMock* profile,
      ProfileSyncService* service) {
    return new AutofillDataTypeController(factory,
        profile,
        service);
  }

  void SetExpectation(ProfileSyncFactoryMock* factory,
      ProfileSyncService* service,
      WebDatabase* wd,
      PersonalDataManager* pdm,
      DataTypeController* dtc) {
    EXPECT_CALL(*factory, CreateAutofillSyncComponents(_,_,_,_)).
        WillOnce(MakeAutofillSyncComponents(service, wd, pdm, dtc));
  }
};

class AutofillProfileFactory : public AbstractAutofillFactory {
 public:
  browser_sync::AutofillDataTypeController* CreateDataTypeController(
      ProfileSyncFactory *factory,
      ProfileMock* profile,
      ProfileSyncService* service) {
    return new AutofillProfileDataTypeController(factory,
        profile,
        service);
  }

  void SetExpectation(ProfileSyncFactoryMock* factory,
      ProfileSyncService* service,
      WebDatabase* wd,
      PersonalDataManager* pdm,
      DataTypeController* dtc) {
    EXPECT_CALL(*factory, CreateAutofillProfileSyncComponents(_,_,_,_)).
        WillOnce(MakeAutofillProfileSyncComponents(service, wd, pdm, dtc));
  }
};

class PersonalDataManagerMock: public PersonalDataManager {
 public:
  MOCK_CONST_METHOD0(IsDataLoaded, bool());
  MOCK_METHOD0(LoadProfiles, void());
  MOCK_METHOD0(LoadCreditCards, void());
  MOCK_METHOD0(Refresh, void());
};
template <class T> class AddAutofillTask;

class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
 protected:
  ProfileSyncServiceAutofillTest() : db_thread_(BrowserThread::DB) {}

  AutofillProfileFactory profile_factory_;
  AutofillEntryFactory entry_factory_;

  AbstractAutofillFactory* GetFactory(syncable::ModelType type) {
    if (type == syncable::AUTOFILL) {
      return &entry_factory_;
    } else if (type == syncable::AUTOFILL_PROFILE) {
      return &profile_factory_;
    } else {
      NOTREACHED();
      return NULL;
    }
  }
  virtual void SetUp() {
    profile_.CreateRequestContext();
    web_database_.reset(new WebDatabaseFake(&autofill_table_));
    web_data_service_ = new WebDataServiceFake(web_database_.get());
    personal_data_manager_ = new PersonalDataManagerMock();
    EXPECT_CALL(*personal_data_manager_, LoadProfiles()).Times(1);
    EXPECT_CALL(*personal_data_manager_, LoadCreditCards()).Times(1);
    personal_data_manager_->Init(&profile_);
    db_thread_.Start();

    notification_service_ = new ThreadNotificationService(&db_thread_);
    notification_service_->Init();
  }

  virtual void TearDown() {
    service_.reset();
    notification_service_->TearDown();
    db_thread_.Stop();
    {
      // The request context gets deleted on the I/O thread. To prevent a leak
      // supply one here.
      BrowserThread io_thread(BrowserThread::IO, MessageLoop::current());
      profile_.ResetRequestContext();
    }
    MessageLoop::current()->RunAllPending();
  }

  void StartSyncService(Task* task,
                        bool will_fail_association,
                        syncable::ModelType type) {
    AbstractAutofillFactory* factory = GetFactory(type);
    service_.reset(
        new TestProfileSyncService(&factory_, &profile_, "test_user", false,
                                   task));
    AutofillDataTypeController* data_type_controller =
        factory->CreateDataTypeController(&factory_,
            &profile_,
            service_.get());
    SyncBackendHostForProfileSyncTest::
        SetDefaultExpectationsForWorkerCreation(&profile_);

    factory->SetExpectation(&factory_,
                            service_.get(),
                            web_database_.get(),
                            personal_data_manager_.get(),
                            data_type_controller);

    EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
        WillOnce(ReturnNewDataTypeManager());

    EXPECT_CALL(profile_, GetWebDataService(_)).
        WillOnce(Return(web_data_service_.get()));

    EXPECT_CALL(profile_, GetPersonalDataManager()).
        WillRepeatedly(Return(personal_data_manager_.get()));

    EXPECT_CALL(*personal_data_manager_, IsDataLoaded()).
        WillRepeatedly(Return(true));

     // We need tokens to get the tests going
    token_service_.IssueAuthTokenForTest(
        GaiaConstants::kSyncService, "token");

    EXPECT_CALL(profile_, GetTokenService()).
        WillRepeatedly(Return(&token_service_));

    service_->RegisterDataTypeController(data_type_controller);
    service_->Initialize();
    MessageLoop::current()->Run();
  }

  bool AddAutofillSyncNode(const AutofillEntry& entry) {
    sync_api::WriteTransaction trans(service_->GetUserShare());
    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByTagLookup(browser_sync::kAutofillTag))
      return false;

    sync_api::WriteNode node(&trans);
    std::string tag = AutofillModelAssociator::KeyToTag(entry.key().name(),
                                                        entry.key().value());
    if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag))
      return false;

    AutofillChangeProcessor::WriteAutofillEntry(entry, &node);
    return true;
  }

  bool AddAutofillSyncNode(const AutofillProfile& profile) {
    sync_api::WriteTransaction trans(service_->GetUserShare());
    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByTagLookup(browser_sync::kAutofillProfileTag))
      return false;
    sync_api::WriteNode node(&trans);
    std::string tag = profile.guid();
    if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE,
        autofill_root, tag))
      return false;
    AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node);
    return true;
  }

  bool GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries,
                                    std::vector<AutofillProfile>* profiles) {
    sync_api::ReadTransaction trans(service_->GetUserShare());
    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByTagLookup(browser_sync::kAutofillTag))
      return false;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return false;

      const sync_pb::AutofillSpecifics& autofill(
          child_node.GetAutofillSpecifics());
      if (autofill.has_value()) {
        AutofillKey key(UTF8ToUTF16(autofill.name()),
                        UTF8ToUTF16(autofill.value()));
        std::vector<base::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));
      } else if (autofill.has_profile()) {
        AutofillProfile p;
        p.set_guid(autofill.profile().guid());
        AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p,
            autofill.profile());
        profiles->push_back(p);
      }
      child_id = child_node.GetSuccessorId();
    }
    return true;
  }

  bool GetAutofillProfilesFromSyncDBUnderProfileNode(
      std::vector<AutofillProfile>* profiles) {
    sync_api::ReadTransaction trans(service_->GetUserShare());
    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByTagLookup(browser_sync::kAutofillProfileTag))
      return false;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return false;

      const sync_pb::AutofillProfileSpecifics& autofill(
          child_node.GetAutofillProfileSpecifics());
        AutofillProfile p;
        p.set_guid(autofill.guid());
        AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p,
            autofill);
        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,
                                         time_t timestamp0,
                                         time_t timestamp1) {
    std::vector<Time> timestamps;
    if (timestamp0 > 0)
      timestamps.push_back(Time::FromTimeT(timestamp0));
    if (timestamp1 > 0)
      timestamps.push_back(Time::FromTimeT(timestamp1));
    return AutofillEntry(
        AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
  }

  static AutofillEntry MakeAutofillEntry(const char* name,
                                         const char* value,
                                         time_t timestamp) {
    return MakeAutofillEntry(name, value, timestamp, -1);
  }

  friend class AddAutofillTask<AutofillEntry>;
  friend class AddAutofillTask<AutofillProfile>;
  friend class FakeServerUpdater;

  BrowserThread db_thread_;
  scoped_refptr<ThreadNotificationService> notification_service_;

  ProfileMock profile_;
  AutofillTableMock autofill_table_;
  scoped_ptr<WebDatabaseFake> web_database_;
  scoped_refptr<WebDataService> web_data_service_;
  scoped_refptr<PersonalDataManagerMock> personal_data_manager_;
};

template <class T>
class AddAutofillTask : public Task {
 public:
  AddAutofillTask(ProfileSyncServiceAutofillTest* test,
                         const std::vector<T>& entries)
      : test_(test), entries_(entries), success_(false) {
  }

  virtual void Run() {
    if (!test_->CreateRoot(GetModelType<T>()))
      return;
    for (size_t i = 0; i < entries_.size(); ++i) {
      if (!test_->AddAutofillSyncNode(entries_[i]))
        return;
    }
    success_ = true;
  }
  bool success() { return success_; }

 private:
  ProfileSyncServiceAutofillTest* test_;
  const std::vector<T>& entries_;
  bool success_;
};

// Overload write transaction to use custom NotifyTransactionComplete
static const bool kLoggingInfo = true;
class WriteTransactionTest: public WriteTransaction {
 public:
  WriteTransactionTest(const syncable::ScopedDirLookup& directory,
                       WriterTag writer, const char* source_file,
                       int line,
                       scoped_ptr<WaitableEvent> *wait_for_syncapi)
      : WriteTransaction(directory, writer, source_file, line),
        wait_for_syncapi_(wait_for_syncapi) { }

  virtual void NotifyTransactionComplete(syncable::ModelTypeBitSet types) {
    // 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:
  scoped_ptr<WaitableEvent> *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,
                    scoped_ptr<WaitableEvent> *wait_for_start,
                    scoped_ptr<WaitableEvent> *wait_for_syncapi)
      : entry_(ProfileSyncServiceAutofillTest::MakeAutofillEntry("0", "0", 0)),
        service_(service),
        wait_for_start_(wait_for_start),
        wait_for_syncapi_(wait_for_syncapi),
        is_finished_(false, false) { }

  void Update() {
    // This gets called in a modelsafeworker thread.
    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));

    sync_api::UserShare* user_share = service_->GetUserShare();
    syncable::DirectoryManager* dir_manager = user_share->dir_manager.get();
    syncable::ScopedDirLookup dir(dir_manager, user_share->name);
    ASSERT_TRUE(dir.good());

    // Create autofill protobuf
    std::string tag = AutofillModelAssociator::KeyToTag(entry_.key().name(),
                                                        entry_.key().value());
    sync_pb::AutofillSpecifics new_autofill;
    new_autofill.set_name(UTF16ToUTF8(entry_.key().name()));
    new_autofill.set_value(UTF16ToUTF8(entry_.key().value()));
    const std::vector<base::Time>& ts(entry_.timestamps());
    for (std::vector<base::Time>::const_iterator timestamp = ts.begin();
         timestamp != ts.end(); ++timestamp) {
      new_autofill.add_usage_timestamp(timestamp->ToInternalValue());
    }

    sync_pb::EntitySpecifics entity_specifics;
    entity_specifics.MutableExtension(sync_pb::autofill)->
        CopyFrom(new_autofill);

    {
      // Tell main thread we've started
      (*wait_for_start_)->Signal();

      // Create write transaction.
      WriteTransactionTest trans(dir, UNITTEST, __FILE__, __LINE__,
                                 wait_for_syncapi_);

      // Create actual entry based on autofill protobuf information.
      // Simulates effects of SyncerUtil::UpdateLocalDataFromServerData
      MutableEntry parent(&trans, GET_BY_SERVER_TAG, kAutofillTag);
      MutableEntry item(&trans, CREATE, parent.Get(syncable::ID), tag);
      ASSERT_TRUE(item.good());
      item.Put(SPECIFICS, entity_specifics);
      item.Put(SERVER_SPECIFICS, entity_specifics);
      item.Put(BASE_VERSION, 1);
      syncable::Id server_item_id = service_->id_factory()->NewServerId();
      item.Put(syncable::ID, server_item_id);
      syncable::Id new_predecessor;
      ASSERT_TRUE(item.PutPredecessor(new_predecessor));
    }
    VLOG(1) << "FakeServerUpdater finishing.";
    is_finished_.Signal();
  }

  void CreateNewEntry(const AutofillEntry& entry) {
    entry_ = entry;
    scoped_ptr<Callback0::Type> c(NewCallback((FakeServerUpdater *)this,
                                              &FakeServerUpdater::Update));
    std::vector<browser_sync::ModelSafeWorker*> workers;
    service_->GetBackendForTest()->GetWorkers(&workers);

    ASSERT_FALSE(BrowserThread::CurrentlyOn(BrowserThread::DB));
    if (!BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
         NewRunnableMethod(this, &FakeServerUpdater::Update))) {
      NOTREACHED() << "Failed to post task to the db thread.";
      return;
    }
  }

  void CreateNewEntryAndWait(const AutofillEntry& entry) {
    entry_ = entry;
    scoped_ptr<Callback0::Type> c(NewCallback((FakeServerUpdater *)this,
                                              &FakeServerUpdater::Update));
    std::vector<browser_sync::ModelSafeWorker*> workers;
    service_->GetBackendForTest()->GetWorkers(&workers);

    ASSERT_FALSE(BrowserThread::CurrentlyOn(BrowserThread::DB));
    is_finished_.Reset();
    if (!BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
         NewRunnableMethod(this, &FakeServerUpdater::Update))) {
      NOTREACHED() << "Failed to post task to the db thread.";
      return;
    }
    is_finished_.Wait();
  }

 private:
  friend class base::RefCountedThreadSafe<FakeServerUpdater>;
  ~FakeServerUpdater() { }

  AutofillEntry entry_;
  TestProfileSyncService *service_;
  scoped_ptr<WaitableEvent> *wait_for_start_;
  scoped_ptr<WaitableEvent> *wait_for_syncapi_;
  WaitableEvent is_finished_;
  syncable::Id parent_id_;
};

// 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(NULL, true, syncable::AUTOFILL);
  EXPECT_TRUE(service_->unrecoverable_error_detected());
}

TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
  EXPECT_CALL(autofill_table_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  CreateRootTask task(this, syncable::AUTOFILL);
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.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(SetArgumentPointee<0>(entries), Return(true)));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  CreateRootTask task(this, syncable::AUTOFILL);
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());
  std::vector<AutofillEntry> sync_entries;
  std::vector<AutofillProfile> sync_profiles;
  ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
  ASSERT_EQ(1U, entries.size());
  EXPECT_TRUE(entries[0] == sync_entries[0]);
  EXPECT_EQ(0U, sync_profiles.size());
}

TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {

  std::vector<AutofillProfile*> profiles;
  std::vector<AutofillProfile> expected_profiles;
  // Owned by GetAutofillProfiles caller.
  AutofillProfile* profile0 = new AutofillProfile;
  autofill_test::SetProfileInfoWithGuid(profile0,
      "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing",
      "Mitchell", "Morrison",
      "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
      "91601", "US", "12345678910", "01987654321");
  profiles.push_back(profile0);
  expected_profiles.push_back(*profile0);
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(profiles), Return(true)));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  SetIdleChangeProcessorExpectations();
  CreateRootTask task(this, syncable::AUTOFILL_PROFILE);
  StartSyncService(&task, false, syncable::AUTOFILL_PROFILE);
  ASSERT_TRUE(task.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(SetArgumentPointee<0>(entries), Return(true)));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  CreateRootTask task(this, syncable::AUTOFILL);
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.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(SetArgumentPointee<0>(native_entries), Return(true)));

  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));

  std::vector<AutofillEntry> sync_entries;
  sync_entries.push_back(sync_entry);

  AddAutofillTask<AutofillEntry> task(this, sync_entries);

  EXPECT_CALL(autofill_table_, UpdateAutofillEntries(ElementsAre(sync_entry))).
      WillOnce(Return(true));

  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.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_TRUE(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(SetArgumentPointee<0>(native_entries), Return(true)));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));

  std::vector<AutofillEntry> sync_entries;
  sync_entries.push_back(sync_entry);
  AddAutofillTask<AutofillEntry> task(this, sync_entries);

  EXPECT_CALL(autofill_table_,
      UpdateAutofillEntries(ElementsAre(merged_entry))).WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.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_TRUE(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", "01987654321");

  AutofillProfile* native_profile = new AutofillProfile;
  autofill_test::SetProfileInfoWithGuid(native_profile,
      "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing", "Alicia", "Saenz",
      "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
      "32801", "US", "19482937549", "13502849239");

  std::vector<AutofillProfile*> native_profiles;
  native_profiles.push_back(native_profile);
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillTask<AutofillProfile> task(this, sync_profiles);

  EXPECT_CALL(autofill_table_, UpdateAutofillProfile(_)).
      WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL_PROFILE);
  ASSERT_TRUE(task.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]));
}

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", "01987654321");

  std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
  AutofillProfile* native_profile = new AutofillProfile;
  autofill_test::SetProfileInfoWithGuid(native_profile,
      native_guid.c_str(), "Billing",
      "Mitchell", "Morrison",
      "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
      "91601", "US", "12345678910", "01987654321");

  std::vector<AutofillProfile*> native_profiles;
  native_profiles.push_back(native_profile);
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillTask<AutofillProfile> task(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(&task, false, syncable::AUTOFILL_PROFILE);
  ASSERT_TRUE(task.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]));
  EXPECT_EQ(sync_profile.guid(), new_sync_profiles[0].guid());
}

TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddEntry) {
  EXPECT_CALL(autofill_table_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  SetIdleChangeProcessorExpectations();
  CreateRootTask task(this, syncable::AUTOFILL);
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());

  AutofillEntry added_entry(MakeAutofillEntry("added", "entry", 1));
  std::vector<base::Time> timestamps(added_entry.timestamps());

  EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _)).
      WillOnce(DoAll(SetArgumentPointee<2>(timestamps), Return(true)));

  AutofillChangeList changes;
  changes.push_back(AutofillChange(AutofillChange::ADD, added_entry.key()));
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_ENTRIES_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillChangeList>(&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_TRUE(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();
  CreateRootTask task(this, syncable::AUTOFILL_PROFILE);
  StartSyncService(&task, false, syncable::AUTOFILL_PROFILE);
  ASSERT_TRUE(task.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", "13502849239");

  AutofillProfileChange change(AutofillProfileChange::ADD,
      added_profile.guid(), &added_profile);
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_PROFILE_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillProfileChange>(&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(SetArgumentPointee<0>(original_entries), Return(true)));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  CreateRootTask task(this, syncable::AUTOFILL);
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());

  AutofillEntry updated_entry(MakeAutofillEntry("my", "entry", 1, 2));
  std::vector<base::Time> timestamps(updated_entry.timestamps());

  EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _)).
      WillOnce(DoAll(SetArgumentPointee<2>(timestamps), Return(true)));

  AutofillChangeList changes;
  changes.push_back(AutofillChange(AutofillChange::UPDATE,
                                   updated_entry.key()));
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_ENTRIES_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillChangeList>(&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_TRUE(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(SetArgumentPointee<0>(original_entries), Return(true)));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  CreateRootTask task(this, syncable::AUTOFILL);
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());

  AutofillChangeList changes;
  changes.push_back(AutofillChange(AutofillChange::REMOVE,
                                   original_entry.key()));
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_ENTRIES_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillChangeList>(&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", "13502849239");
  AutofillProfile* native_profile = new AutofillProfile;
  autofill_test::SetProfileInfoWithGuid(native_profile,
      "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine", "Alicia", "Saenz",
      "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
      "32801", "US", "19482937549", "13502849239");

  std::vector<AutofillProfile*> native_profiles;
  native_profiles.push_back(native_profile);
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillTask<AutofillProfile> task(this, sync_profiles);
  EXPECT_CALL(*personal_data_manager_, Refresh());
  StartSyncService(&task, false, syncable::AUTOFILL_PROFILE);
  ASSERT_TRUE(task.success());

  AutofillProfileChange change(AutofillProfileChange::REMOVE,
                               sync_profile.guid(), NULL);
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_PROFILE_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillProfileChange>(&change));

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(
      &new_sync_profiles));
  ASSERT_EQ(0U, new_sync_profiles.size());
}

TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeError) {
  EXPECT_CALL(autofill_table_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh());
  CreateRootTask task(this, syncable::AUTOFILL);
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());

  // Inject an evil entry into the sync db to conflict with the same
  // entry added by the user.
  AutofillEntry evil_entry(MakeAutofillEntry("evil", "entry", 1));
  ASSERT_TRUE(AddAutofillSyncNode(evil_entry));

  AutofillChangeList changes;
  changes.push_back(AutofillChange(AutofillChange::ADD,
                                   evil_entry.key()));
  scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&db_thread_));
  notifier->Notify(NotificationType::AUTOFILL_ENTRIES_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillChangeList>(&changes));

  // Wait for the PPS to shut everything down and signal us.
  ProfileSyncServiceObserverMock observer;
  service_->AddObserver(&observer);
  EXPECT_CALL(observer, OnStateChanged()).WillOnce(QuitUIMessageLoop());
  MessageLoop::current()->Run();
  EXPECT_TRUE(service_->unrecoverable_error_detected());

  // Ensure future autofill notifications don't crash.
  notifier->Notify(NotificationType::AUTOFILL_ENTRIES_CHANGED,
                   Source<WebDataService>(web_data_service_.get()),
                   Details<AutofillChangeList>(&changes));
}

// Crashy, http://crbug.com/57884
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_ServerChangeRace) {
  EXPECT_CALL(autofill_table_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table_, GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table_, UpdateAutofillEntries(_)).
      WillRepeatedly(Return(true));
  EXPECT_CALL(*personal_data_manager_, Refresh()).Times(3);
  CreateRootTask task(this, syncable::AUTOFILL);
  StartSyncService(&task, false, syncable::AUTOFILL);
  ASSERT_TRUE(task.success());

  // (true, false) means we have to reset after |Signal|, init to unsignaled.
  scoped_ptr<WaitableEvent> wait_for_start(new WaitableEvent(true, false));
  scoped_ptr<WaitableEvent> wait_for_syncapi(new WaitableEvent(true, false));
  scoped_refptr<FakeServerUpdater> updater(new FakeServerUpdater(
      service_.get(), &wait_for_start, &wait_for_syncapi));

  // 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));
  VLOG(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->CreateNewEntryAndWait(MakeAutofillEntry("server2", "entry2", 3));

  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++) {
    VLOG(1) << "Entry " << i << ": " << sync_entries[i].key().name()
            << ", " << sync_entries[i].key().value();
  }
}