root/components/password_manager/core/browser/password_syncable_service_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetPasswordSpecifics
  2. PasswordsEqual
  3. CreateSyncData
  4. CreateSyncChange
  5. VerifyAdd
  6. VerifyUpdate
  7. VerifyDelete
  8. TestSyncChangeProcessor
  9. TestSyncChangeProcessor
  10. ProcessSyncChanges
  11. GetAllSyncData
  12. SetExpectedDBChanges
  13. SetExpectedSyncChanges
  14. TestSyncChanges
  15. VerifyChange
  16. password_store
  17. service
  18. ReleaseSyncableService
  19. verifier
  20. CreateSyncChangeProcessor
  21. SetPasswordStoreData
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F
  31. TEST_F

// Copyright 2014 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 "components/password_manager/core/browser/password_syncable_service.h"

#include <algorithm>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "sync/api/sync_change_processor.h"
#include "sync/api/sync_error.h"
#include "sync/api/sync_error_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using syncer::SyncChange;
using syncer::SyncData;
using syncer::SyncDataList;
using syncer::SyncError;
using testing::Invoke;
using testing::Return;
using testing::SetArgPointee;
using testing::_;

namespace {

typedef std::vector<SyncChange> SyncChangeList;

const sync_pb::PasswordSpecificsData& GetPasswordSpecifics(
    const syncer::SyncData& sync_data) {
  const sync_pb::EntitySpecifics& specifics = sync_data.GetSpecifics();
  return specifics.password().client_only_encrypted_data();
}

void PasswordsEqual(const sync_pb::PasswordSpecificsData& expected_password,
                    const sync_pb::PasswordSpecificsData& actual_password) {
  EXPECT_EQ(expected_password.scheme(), actual_password.scheme());
  EXPECT_EQ(expected_password.signon_realm(), actual_password.signon_realm());
  EXPECT_EQ(expected_password.origin(), actual_password.origin());
  EXPECT_EQ(expected_password.action(), actual_password.action());
  EXPECT_EQ(expected_password.username_element(),
            actual_password.username_element());
  EXPECT_EQ(expected_password.password_element(),
            actual_password.password_element());
  EXPECT_EQ(expected_password.username_value(),
            actual_password.username_value());
  EXPECT_EQ(expected_password.password_value(),
            actual_password.password_value());
  EXPECT_EQ(expected_password.ssl_valid(), actual_password.ssl_valid());
  EXPECT_EQ(expected_password.preferred(), actual_password.preferred());
  EXPECT_EQ(expected_password.date_created(), actual_password.date_created());
  EXPECT_EQ(expected_password.blacklisted(), actual_password.blacklisted());
}

// Creates a sync data consisting of password specifics. The sign on realm is
// set to |signon_realm|.
SyncData CreateSyncData(const std::string& signon_realm) {
  sync_pb::EntitySpecifics password_data;
  sync_pb::PasswordSpecificsData* password_specifics =
      password_data.mutable_password()->mutable_client_only_encrypted_data();
  password_specifics->set_signon_realm(signon_realm);

  std::string tag = MakePasswordSyncTag(*password_specifics);
  return syncer::SyncData::CreateLocalData(tag, tag, password_data);
}

SyncChange CreateSyncChange(const autofill::PasswordForm& password,
                            SyncChange::SyncChangeType type) {
  SyncData data = SyncDataFromPassword(password);
  return SyncChange(FROM_HERE, type, data);
}

// A testable implementation of the |PasswordSyncableService| that mocks
// out all interaction with the password database.
class MockPasswordSyncableService : public PasswordSyncableService {
 public:
  explicit MockPasswordSyncableService(PasswordStore* password_store)
      : PasswordSyncableService(password_store) {}
  virtual ~MockPasswordSyncableService() {}

  MOCK_METHOD1(NotifyPasswordStoreOfLoginChanges,
               void (const PasswordStoreChangeList&));

  MOCK_METHOD1(StartSyncFlare, void(syncer::ModelType));
};

// Class to verify the arguments passed to |PasswordStore|.
class PasswordStoreDataVerifier {
 public:
  PasswordStoreDataVerifier() {}
  ~PasswordStoreDataVerifier() {
    EXPECT_TRUE(expected_db_add_changes_.empty());
    EXPECT_TRUE(expected_db_update_changes_.empty());
    EXPECT_TRUE(expected_db_delete_changes_.empty());
  }

  class TestSyncChangeProcessor;

  // Sets expected changes to the password database.
  void SetExpectedDBChanges(
      const SyncDataList& add_forms,
      const std::vector<autofill::PasswordForm*>& update_forms,
      const std::vector<autofill::PasswordForm*>& delete_forms,
      MockPasswordStore* password_store);
  // Sets expected changes to TestSyncChangeProcessor.
  void SetExpectedSyncChanges(SyncChangeList list);

 private:
  // Checks that |change_list| matches |expected_sync_change_list_|.
  SyncError TestSyncChanges(const SyncChangeList& change_list);

  // Verifies that the |password| is present in the |expected_db_add_changes_|
  // list. If found, |password| would be removed from
  // |expected_db_add_changes_| list.
  PasswordStoreChangeList VerifyAdd(const autofill::PasswordForm& password) {
    return VerifyChange(PasswordStoreChange::ADD, password,
                        &expected_db_add_changes_);
  }

  // Verifies that the |password| is present in the
  // |expected_db_update_changes_| list. If found, |password| would be removed
  // from |expected_db_update_changes_| list.
  PasswordStoreChangeList VerifyUpdate(const autofill::PasswordForm& password) {
    return VerifyChange(PasswordStoreChange::UPDATE, password,
                        &expected_db_update_changes_);
  }

  // Verifies that the |password| is present in the
  // |expected_db_delete_changes_| list. If found, |password| would be removed
  // from |expected_db_delete_changes_| list.
  PasswordStoreChangeList VerifyDelete(const autofill::PasswordForm& password) {
    return VerifyChange(PasswordStoreChange::REMOVE, password,
                        &expected_db_delete_changes_);
  }

  static PasswordStoreChangeList VerifyChange(
      PasswordStoreChange::Type type,
      const autofill::PasswordForm& password,
      std::vector<autofill::PasswordForm>* password_list);

  std::vector<autofill::PasswordForm> expected_db_add_changes_;
  std::vector<autofill::PasswordForm> expected_db_update_changes_;
  std::vector<autofill::PasswordForm> expected_db_delete_changes_;
  SyncChangeList expected_sync_change_list_;

  DISALLOW_COPY_AND_ASSIGN(PasswordStoreDataVerifier);
};

class PasswordStoreDataVerifier::TestSyncChangeProcessor
    : public syncer::SyncChangeProcessor {
 public:
  explicit TestSyncChangeProcessor(PasswordStoreDataVerifier* verifier)
      : verifier_(verifier) {
  }
  virtual ~TestSyncChangeProcessor() {}

  virtual SyncError ProcessSyncChanges(const tracked_objects::Location&,
                                       const SyncChangeList& list) OVERRIDE {
    return verifier_->TestSyncChanges(list);
  }

  virtual SyncDataList GetAllSyncData(syncer::ModelType type) const OVERRIDE {
    return SyncDataList();
  }
 private:
  PasswordStoreDataVerifier* verifier_;

  DISALLOW_COPY_AND_ASSIGN(TestSyncChangeProcessor);
};

void PasswordStoreDataVerifier::SetExpectedDBChanges(
    const SyncDataList& add_forms,
    const std::vector<autofill::PasswordForm*>& update_forms,
    const std::vector<autofill::PasswordForm*>& delete_forms,
    MockPasswordStore* password_store) {
  DCHECK(expected_db_add_changes_.empty());
  DCHECK(expected_db_update_changes_.empty());
  DCHECK(password_store);

  for (SyncDataList::const_iterator it = add_forms.begin();
       it != add_forms.end(); ++it) {
    autofill::PasswordForm form;
    PasswordFromSpecifics(GetPasswordSpecifics(*it), &form);
    expected_db_add_changes_.push_back(form);
  }
  if (expected_db_add_changes_.empty()) {
    EXPECT_CALL(*password_store, AddLoginImpl(_)).Times(0);
  } else {
    EXPECT_CALL(*password_store, AddLoginImpl(_))
        .Times(expected_db_add_changes_.size())
        .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyAdd));
  }

  for (std::vector<autofill::PasswordForm*>::const_iterator it =
           update_forms.begin();
       it != update_forms.end(); ++it) {
    expected_db_update_changes_.push_back(**it);
  }
  if (expected_db_update_changes_.empty()) {
    EXPECT_CALL(*password_store, UpdateLoginImpl(_)).Times(0);
  } else {
    EXPECT_CALL(*password_store, UpdateLoginImpl(_))
        .Times(expected_db_update_changes_.size())
        .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyUpdate));
  }

  for (std::vector<autofill::PasswordForm*>::const_iterator it =
           delete_forms.begin();
       it != delete_forms.end(); ++it) {
    expected_db_delete_changes_.push_back(**it);
  }
  if (expected_db_delete_changes_.empty()) {
    EXPECT_CALL(*password_store, RemoveLoginImpl(_)).Times(0);
  } else {
    EXPECT_CALL(*password_store, RemoveLoginImpl(_))
        .Times(expected_db_delete_changes_.size())
        .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyDelete));
  }
}

void PasswordStoreDataVerifier::SetExpectedSyncChanges(SyncChangeList list) {
  expected_sync_change_list_.swap(list);
}

SyncError PasswordStoreDataVerifier::TestSyncChanges(
    const SyncChangeList& change_list) {
  for (SyncChangeList::const_iterator it = change_list.begin();
      it != change_list.end(); ++it) {
    const SyncChange& data = *it;
    const sync_pb::PasswordSpecificsData& actual_password(
        GetPasswordSpecifics(data.sync_data()));
    std::string actual_tag = MakePasswordSyncTag(actual_password);

    bool matched = false;
    for (SyncChangeList::iterator expected_it =
             expected_sync_change_list_.begin();
         expected_it != expected_sync_change_list_.end();
         ++expected_it) {
      const sync_pb::PasswordSpecificsData& expected_password(
          GetPasswordSpecifics(expected_it->sync_data()));
      if (actual_tag == MakePasswordSyncTag(expected_password)) {
        PasswordsEqual(expected_password, actual_password);
        EXPECT_EQ(expected_it->change_type(), data.change_type());
        matched = true;
        break;
      }
    }
    EXPECT_TRUE(matched) << actual_tag;
  }
  EXPECT_EQ(expected_sync_change_list_.size(), change_list.size());
  return SyncError();
}

// static
PasswordStoreChangeList PasswordStoreDataVerifier::VerifyChange(
    PasswordStoreChange::Type type,
    const autofill::PasswordForm& password,
    std::vector<autofill::PasswordForm>* password_list) {
  std::vector<autofill::PasswordForm>::iterator it =
      std::find(password_list->begin(), password_list->end(), password);
  EXPECT_NE(password_list->end(), it);
  password_list->erase(it);
  return PasswordStoreChangeList(1, PasswordStoreChange(type, password));
}

class PasswordSyncableServiceWrapper {
 public:
  PasswordSyncableServiceWrapper() {
    password_store_ = new MockPasswordStore;
    service_.reset(new MockPasswordSyncableService(password_store_));
  }

  ~PasswordSyncableServiceWrapper() {
    password_store_->Shutdown();
  }

  MockPasswordStore* password_store() {
    return password_store_;
  }

  MockPasswordSyncableService* service() {
    return service_.get();
  }

  // Returnes the scoped_ptr to |service_| thus NULLing out it.
  scoped_ptr<syncer::SyncChangeProcessor> ReleaseSyncableService() {
    return service_.PassAs<syncer::SyncChangeProcessor>();
  }

  PasswordStoreDataVerifier* verifier() {
    return &verifier_;
  }

  scoped_ptr<syncer::SyncChangeProcessor> CreateSyncChangeProcessor() {
    return make_scoped_ptr<syncer::SyncChangeProcessor>(
        new PasswordStoreDataVerifier::TestSyncChangeProcessor(verifier()));
  }

  // Sets the data that will be returned to the caller accessing password store.
  void SetPasswordStoreData(
      const std::vector<autofill::PasswordForm*>& forms,
      const std::vector<autofill::PasswordForm*>& blacklist_forms) {
    EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
        .WillOnce(Invoke(AppendVector(forms)))
        .RetiresOnSaturation();
    EXPECT_CALL(*password_store_, FillBlacklistLogins(_))
        .WillOnce(Invoke(AppendVector(blacklist_forms)))
        .RetiresOnSaturation();
  }

 protected:
  scoped_refptr<MockPasswordStore> password_store_;
  scoped_ptr<MockPasswordSyncableService> service_;
  PasswordStoreDataVerifier verifier_;

 private:
  struct AppendVector {
    explicit AppendVector(
        const std::vector<autofill::PasswordForm*>& append_forms)
        : append_forms_(append_forms) {
    }

    ~AppendVector() {}

    bool operator()(std::vector<autofill::PasswordForm*>* forms) const {
      forms->insert(forms->end(), append_forms_.begin(), append_forms_.end());
      return true;
    }

    std::vector<autofill::PasswordForm*> append_forms_;
  };

  DISALLOW_COPY_AND_ASSIGN(PasswordSyncableServiceWrapper);
};

class PasswordSyncableServiceTest : public testing::Test,
                                    public PasswordSyncableServiceWrapper {
 public:
  PasswordSyncableServiceTest() {}
  virtual ~PasswordSyncableServiceTest() {}
};


// Both sync and password db have data that are not present in the other.
TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  std::vector<autofill::PasswordForm*> forms;
  forms.push_back(form1.release());
  SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>());

  SyncData sync_data = CreateSyncData("def");
  SyncDataList list;
  list.push_back(sync_data);

  verifier()->SetExpectedDBChanges(list,
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(
      SyncChangeList(1, CreateSyncChange(*forms[0], SyncChange::ACTION_ADD)));
  EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_));

  service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                      list,
                                      CreateSyncChangeProcessor(),
                                      scoped_ptr<syncer::SyncErrorFactory>());
}

// Sync has data that is not present in the password db.
TEST_F(PasswordSyncableServiceTest, AdditionOnlyInSync) {
  SetPasswordStoreData(std::vector<autofill::PasswordForm*>(),
                       std::vector<autofill::PasswordForm*>());

  SyncData sync_data = CreateSyncData("def");
  SyncDataList list;
  list.push_back(sync_data);

  verifier()->SetExpectedDBChanges(list,
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(SyncChangeList());
  EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_));

  service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                      list,
                                      CreateSyncChangeProcessor(),
                                      scoped_ptr<syncer::SyncErrorFactory>());
}

// Passwords db has data that is not present in sync.
TEST_F(PasswordSyncableServiceTest, AdditionOnlyInPasswordStore) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  std::vector<autofill::PasswordForm*> forms;
  forms.push_back(form1.release());
  SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>());

  verifier()->SetExpectedDBChanges(SyncDataList(),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(
      SyncChangeList(1, CreateSyncChange(*forms[0], SyncChange::ACTION_ADD)));
  EXPECT_CALL(*service_,
              NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList()));

  service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                      SyncDataList(),
                                      CreateSyncChangeProcessor(),
                                      scoped_ptr<syncer::SyncErrorFactory>());
}

// Both passwords db and sync contain the same data.
TEST_F(PasswordSyncableServiceTest, BothInSync) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  std::vector<autofill::PasswordForm*> forms;
  forms.push_back(form1.release());
  SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>());

  verifier()->SetExpectedDBChanges(SyncDataList(),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(SyncChangeList());
  EXPECT_CALL(*service_,
              NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList()));

  service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                      SyncDataList(1, CreateSyncData("abc")),
                                      CreateSyncChangeProcessor(),
                                      scoped_ptr<syncer::SyncErrorFactory>());
}

// Both passwords db and sync have the same data but they need to be merged
// as some fields of the data differ.
TEST_F(PasswordSyncableServiceTest, Merge) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  form1->action = GURL("http://pie.com");
  form1->date_created = base::Time::Now();
  std::vector<autofill::PasswordForm*> forms;
  forms.push_back(form1.release());
  SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>());

  verifier()->SetExpectedDBChanges(SyncDataList(),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(
      SyncChangeList(1, CreateSyncChange(*forms[0],
                                         SyncChange::ACTION_UPDATE)));

  EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_));

  service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                      SyncDataList(1, CreateSyncData("abc")),
                                      CreateSyncChangeProcessor(),
                                      scoped_ptr<syncer::SyncErrorFactory>());
}

// Initiate sync due to local DB changes.
TEST_F(PasswordSyncableServiceTest, PasswordStoreChanges) {
  // Set the sync change processor first.
  SetPasswordStoreData(std::vector<autofill::PasswordForm*>(),
                       std::vector<autofill::PasswordForm*>());
  verifier()->SetExpectedSyncChanges(SyncChangeList());
  EXPECT_CALL(*service_,
              NotifyPasswordStoreOfLoginChanges(PasswordStoreChangeList()));
  service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
                                     SyncDataList(),
                                     CreateSyncChangeProcessor(),
                                     scoped_ptr<syncer::SyncErrorFactory>());

  autofill::PasswordForm form1;
  form1.signon_realm = "abc";
  autofill::PasswordForm form2;
  form2.signon_realm = "def";
  autofill::PasswordForm form3;
  form3.signon_realm = "xyz";

  SyncChangeList sync_list;
  sync_list.push_back(CreateSyncChange(form1, SyncChange::ACTION_ADD));
  sync_list.push_back(CreateSyncChange(form2, SyncChange::ACTION_UPDATE));
  sync_list.push_back(CreateSyncChange(form3, SyncChange::ACTION_DELETE));

  verifier()->SetExpectedDBChanges(SyncDataList(),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  verifier()->SetExpectedSyncChanges(sync_list);

  PasswordStoreChangeList list;
  list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form1));
  list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form2));
  list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form3));
  service()->ActOnPasswordStoreChanges(list);
}

// Process all types of changes from sync.
TEST_F(PasswordSyncableServiceTest, ProcessSyncChanges) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  form1->action = GURL("http://foo.com");
  scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm);
  form2->signon_realm = "xyz";
  form2->action = GURL("http://bar.com");
  form2->date_created = base::Time::Now();
  form2->blacklisted_by_user = true;
  std::vector<autofill::PasswordForm*> forms(1, form1.release());
  std::vector<autofill::PasswordForm*> blacklist_forms(1, form2.release());
  SetPasswordStoreData(forms, blacklist_forms);

  SyncData add_data = CreateSyncData("def");
  autofill::PasswordForm updated_form = *forms[0];
  updated_form.date_created = base::Time::Now();
  std::vector<autofill::PasswordForm*> updated_passwords(1, &updated_form);
  std::vector<autofill::PasswordForm*> deleted_passwords(1, blacklist_forms[0]);
  verifier()->SetExpectedDBChanges(SyncDataList(1, add_data),
                                   updated_passwords,
                                   deleted_passwords,
                                   password_store());

  SyncChangeList list;
  list.push_back(SyncChange(FROM_HERE,
                            syncer::SyncChange::ACTION_ADD,
                            add_data));
  list.push_back(SyncChange(FROM_HERE,
                            syncer::SyncChange::ACTION_UPDATE,
                            SyncDataFromPassword(updated_form)));
  list.push_back(CreateSyncChange(*blacklist_forms[0],
                                  syncer::SyncChange::ACTION_DELETE));
  EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_));
  service()->ProcessSyncChanges(FROM_HERE, list);
}

// Retrives sync data from the model.
TEST_F(PasswordSyncableServiceTest, GetAllSyncData) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  form1->action = GURL("http://foo.com");
  scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm);
  form2->signon_realm = "xyz";
  form2->action = GURL("http://bar.com");
  form2->blacklisted_by_user = true;
  std::vector<autofill::PasswordForm*> forms(1, form1.release());
  std::vector<autofill::PasswordForm*> blacklist_forms(1, form2.release());
  SetPasswordStoreData(forms, blacklist_forms);

  SyncDataList expected_list;
  expected_list.push_back(SyncDataFromPassword(*forms[0]));
  expected_list.push_back(SyncDataFromPassword(*blacklist_forms[0]));

  verifier()->SetExpectedDBChanges(SyncDataList(),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());

  SyncDataList actual_list = service()->GetAllSyncData(syncer::PASSWORDS);
  EXPECT_EQ(expected_list.size(), actual_list.size());
  for (SyncDataList::iterator i(actual_list.begin()), j(expected_list.begin());
       i != actual_list.end() && j != expected_list.end(); ++i, ++j) {
    PasswordsEqual(GetPasswordSpecifics(*j), GetPasswordSpecifics(*i));
  }
}

// Creates 2 PasswordSyncableService instances, merges the content of the first
// one to the second one and back.
TEST_F(PasswordSyncableServiceTest, MergeDataAndPushBack) {
  scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
  form1->signon_realm = "abc";
  form1->action = GURL("http://foo.com");
  std::vector<autofill::PasswordForm*> forms(1, form1.release());
  SetPasswordStoreData(forms, std::vector<autofill::PasswordForm*>());

  PasswordSyncableServiceWrapper other_service_wrapper;
  scoped_ptr<autofill::PasswordForm> form2(new autofill::PasswordForm);
  form2->signon_realm = "xyz";
  form2->action = GURL("http://bar.com");
  syncer::SyncData form2_sync_data = SyncDataFromPassword(*form2);
  other_service_wrapper.SetPasswordStoreData(
      std::vector<autofill::PasswordForm*>(1, form2.release()),
      std::vector<autofill::PasswordForm*>());

  verifier()->SetExpectedDBChanges(SyncDataList(1, form2_sync_data),
                                   std::vector<autofill::PasswordForm*>(),
                                   std::vector<autofill::PasswordForm*>(),
                                   password_store());
  other_service_wrapper.verifier()->SetExpectedDBChanges(
      SyncDataList(1, SyncDataFromPassword(*forms[0])),
      std::vector<autofill::PasswordForm*>(),
      std::vector<autofill::PasswordForm*>(),
      other_service_wrapper.password_store());
  EXPECT_CALL(*service(), NotifyPasswordStoreOfLoginChanges(_));
  EXPECT_CALL(*other_service_wrapper.service(),
              NotifyPasswordStoreOfLoginChanges(_));

  syncer::SyncDataList other_service_data =
      other_service_wrapper.service()->GetAllSyncData(syncer::PASSWORDS);
  service()->MergeDataAndStartSyncing(
      syncer::PASSWORDS,
      other_service_data,
      other_service_wrapper.ReleaseSyncableService(),
      scoped_ptr<syncer::SyncErrorFactory>());
}

// Calls ActOnPasswordStoreChanges without SyncChangeProcessor. StartSyncFlare
// should be called.
TEST_F(PasswordSyncableServiceTest, StartSyncFlare) {
  autofill::PasswordForm form;
  form.signon_realm = "abc";
  PasswordStoreChangeList list;
  list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));

  // No flare and no SyncChangeProcessor, the call shouldn't crash.
  service()->ActOnPasswordStoreChanges(list);

  // Set the flare. It should be called as there is no SyncChangeProcessor.
  service()->InjectStartSyncFlare(
      base::Bind(&MockPasswordSyncableService::StartSyncFlare,
                 base::Unretained(service())));
  EXPECT_CALL(*service(), StartSyncFlare(syncer::PASSWORDS));
  service()->ActOnPasswordStoreChanges(list);
}

}  // namespace

/* [<][>][^][v][top][bottom][index][help] */