Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <vector>
      6 
      7 #include "testing/gtest/include/gtest/gtest.h"
      8 
      9 #include "base/synchronization/waitable_event.h"
     10 #include "base/task.h"
     11 #include "base/test/test_timeouts.h"
     12 #include "base/time.h"
     13 #include "base/utf_string_conversions.h"
     14 #include "chrome/browser/password_manager/password_store.h"
     15 #include "chrome/browser/prefs/pref_service.h"
     16 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
     17 #include "chrome/browser/sync/engine/syncapi.h"
     18 #include "chrome/browser/sync/glue/password_change_processor.h"
     19 #include "chrome/browser/sync/glue/password_data_type_controller.h"
     20 #include "chrome/browser/sync/glue/password_model_associator.h"
     21 #include "chrome/browser/sync/profile_sync_factory.h"
     22 #include "chrome/browser/sync/profile_sync_factory_mock.h"
     23 #include "chrome/browser/sync/profile_sync_service.h"
     24 #include "chrome/browser/sync/profile_sync_test_util.h"
     25 #include "chrome/browser/sync/protocol/password_specifics.pb.h"
     26 #include "chrome/browser/sync/syncable/directory_manager.h"
     27 #include "chrome/browser/sync/syncable/syncable.h"
     28 #include "chrome/browser/sync/test_profile_sync_service.h"
     29 #include "chrome/common/net/gaia/gaia_constants.h"
     30 #include "chrome/common/pref_names.h"
     31 #include "chrome/test/sync/engine/test_id_factory.h"
     32 #include "chrome/test/profile_mock.h"
     33 #include "content/browser/browser_thread.h"
     34 #include "content/common/notification_observer_mock.h"
     35 #include "content/common/notification_source.h"
     36 #include "content/common/notification_type.h"
     37 #include "testing/gmock/include/gmock/gmock.h"
     38 #include "webkit/glue/password_form.h"
     39 
     40 using base::Time;
     41 using browser_sync::PasswordChangeProcessor;
     42 using browser_sync::PasswordDataTypeController;
     43 using browser_sync::PasswordModelAssociator;
     44 using browser_sync::TestIdFactory;
     45 using browser_sync::UnrecoverableErrorHandler;
     46 using sync_api::SyncManager;
     47 using sync_api::UserShare;
     48 using syncable::BASE_VERSION;
     49 using syncable::CREATE;
     50 using syncable::DirectoryManager;
     51 using syncable::IS_DEL;
     52 using syncable::IS_DIR;
     53 using syncable::IS_UNAPPLIED_UPDATE;
     54 using syncable::IS_UNSYNCED;
     55 using syncable::MutableEntry;
     56 using syncable::SERVER_IS_DIR;
     57 using syncable::SERVER_VERSION;
     58 using syncable::SPECIFICS;
     59 using syncable::ScopedDirLookup;
     60 using syncable::UNIQUE_SERVER_TAG;
     61 using syncable::UNITTEST;
     62 using syncable::WriteTransaction;
     63 using testing::_;
     64 using testing::AtLeast;
     65 using testing::DoAll;
     66 using testing::DoDefault;
     67 using testing::ElementsAre;
     68 using testing::Eq;
     69 using testing::Invoke;
     70 using testing::InvokeWithoutArgs;
     71 using testing::Return;
     72 using testing::SaveArg;
     73 using testing::SetArgumentPointee;
     74 using webkit_glue::PasswordForm;
     75 
     76 ACTION_P3(MakePasswordSyncComponents, service, ps, dtc) {
     77   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     78   PasswordModelAssociator* model_associator =
     79       new PasswordModelAssociator(service, ps);
     80   PasswordChangeProcessor* change_processor =
     81       new PasswordChangeProcessor(model_associator, ps, dtc);
     82   return ProfileSyncFactory::SyncComponents(model_associator,
     83                                             change_processor);
     84 }
     85 
     86 ACTION_P(AcquireSyncTransaction, password_test_service) {
     87   // Check to make sure we can aquire a transaction (will crash if a transaction
     88   // is already held by this thread, deadlock if held by another thread).
     89   sync_api::WriteTransaction trans(password_test_service->GetUserShare());
     90   VLOG(1) << "Sync transaction acquired.";
     91 }
     92 
     93 static void QuitMessageLoop() {
     94   MessageLoop::current()->Quit();
     95 }
     96 
     97 class MockPasswordStore : public PasswordStore {
     98  public:
     99   MOCK_METHOD1(RemoveLogin, void(const PasswordForm&));
    100   MOCK_METHOD2(GetLogins, int(const PasswordForm&, PasswordStoreConsumer*));
    101   MOCK_METHOD1(AddLogin, void(const PasswordForm&));
    102   MOCK_METHOD1(UpdateLogin, void(const PasswordForm&));
    103   MOCK_METHOD0(ReportMetrics, void());
    104   MOCK_METHOD0(ReportMetricsImpl, void());
    105   MOCK_METHOD1(AddLoginImpl, void(const PasswordForm&));
    106   MOCK_METHOD1(UpdateLoginImpl, void(const PasswordForm&));
    107   MOCK_METHOD1(RemoveLoginImpl, void(const PasswordForm&));
    108   MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl, void(const base::Time&,
    109                const base::Time&));
    110   MOCK_METHOD2(GetLoginsImpl, void(GetLoginsRequest*, const PasswordForm&));
    111   MOCK_METHOD1(GetAutofillableLoginsImpl, void(GetLoginsRequest*));
    112   MOCK_METHOD1(GetBlacklistLoginsImpl, void(GetLoginsRequest*));
    113   MOCK_METHOD1(FillAutofillableLogins,
    114       bool(std::vector<PasswordForm*>*));
    115   MOCK_METHOD1(FillBlacklistLogins,
    116       bool(std::vector<PasswordForm*>*));
    117 };
    118 
    119 class PasswordTestProfileSyncService : public TestProfileSyncService {
    120  public:
    121   PasswordTestProfileSyncService(ProfileSyncFactory* factory,
    122                                  Profile* profile,
    123                                  const std::string& test_user,
    124                                  bool synchronous_backend_initialization,
    125                                  Task* initial_condition_setup_task,
    126                                  Task* passphrase_accept_task)
    127       : TestProfileSyncService(factory, profile, test_user,
    128                                synchronous_backend_initialization,
    129                                initial_condition_setup_task),
    130         passphrase_accept_task_(passphrase_accept_task) {}
    131 
    132   virtual ~PasswordTestProfileSyncService() {}
    133 
    134   virtual void OnPassphraseAccepted() {
    135     if (passphrase_accept_task_) {
    136       passphrase_accept_task_->Run();
    137     }
    138 
    139     TestProfileSyncService::OnPassphraseAccepted();
    140   }
    141 
    142  private:
    143   Task* passphrase_accept_task_;
    144 };
    145 
    146 class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
    147  public:
    148   sync_api::UserShare* GetUserShare() {
    149     return service_->GetUserShare();
    150   }
    151  protected:
    152   ProfileSyncServicePasswordTest()
    153       : db_thread_(BrowserThread::DB) {
    154   }
    155 
    156   virtual void SetUp() {
    157     profile_.CreateRequestContext();
    158     password_store_ = new MockPasswordStore();
    159     db_thread_.Start();
    160 
    161     notification_service_ = new ThreadNotificationService(&db_thread_);
    162     notification_service_->Init();
    163     registrar_.Add(&observer_,
    164         NotificationType::SYNC_CONFIGURE_DONE,
    165         NotificationService::AllSources());
    166     registrar_.Add(&observer_,
    167         NotificationType::SYNC_CONFIGURE_BLOCKED,
    168         NotificationService::AllSources());
    169   }
    170 
    171   virtual void TearDown() {
    172     password_store_->Shutdown();
    173     service_.reset();
    174     notification_service_->TearDown();
    175     db_thread_.Stop();
    176     {
    177       // The request context gets deleted on the I/O thread. To prevent a leak
    178       // supply one here.
    179       BrowserThread io_thread(BrowserThread::IO, MessageLoop::current());
    180       profile_.ResetRequestContext();
    181     }
    182     MessageLoop::current()->RunAllPending();
    183   }
    184 
    185   static void SignalEvent(base::WaitableEvent* done) {
    186     done->Signal();
    187   }
    188 
    189   void FlushLastDBTask() {
    190     base::WaitableEvent done(false, false);
    191     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
    192        NewRunnableFunction(&ProfileSyncServicePasswordTest::SignalEvent,
    193                            &done));
    194     done.TimedWait(base::TimeDelta::FromMilliseconds(
    195         TestTimeouts::action_timeout_ms()));
    196   }
    197 
    198   void StartSyncService(Task* root_task, Task* node_task) {
    199     if (!service_.get()) {
    200       service_.reset(new PasswordTestProfileSyncService(
    201           &factory_, &profile_, "test_user", false, root_task, node_task));
    202       service_->RegisterPreferences();
    203       profile_.GetPrefs()->SetBoolean(prefs::kSyncPasswords, true);
    204       PasswordDataTypeController* data_type_controller =
    205           new PasswordDataTypeController(&factory_,
    206                                          &profile_,
    207                                          service_.get());
    208 
    209       EXPECT_CALL(factory_, CreatePasswordSyncComponents(_, _, _)).
    210           Times(AtLeast(1)).  // Can be more if we hit NEEDS_CRYPTO.
    211           WillRepeatedly(MakePasswordSyncComponents(service_.get(),
    212                                                     password_store_.get(),
    213                                                     data_type_controller));
    214       EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
    215           WillOnce(ReturnNewDataTypeManager());
    216 
    217       // We need tokens to get the tests going
    218       token_service_.IssueAuthTokenForTest(
    219           GaiaConstants::kSyncService, "token");
    220 
    221       EXPECT_CALL(profile_, GetTokenService()).
    222           WillRepeatedly(Return(&token_service_));
    223 
    224       EXPECT_CALL(profile_, GetPasswordStore(_)).
    225           Times(AtLeast(2)).  // Can be more if we hit NEEDS_CRYPTO.
    226           WillRepeatedly(Return(password_store_.get()));
    227 
    228       EXPECT_CALL(observer_,
    229           Observe(
    230               NotificationType(NotificationType::SYNC_CONFIGURE_DONE),_,_));
    231       EXPECT_CALL(observer_,
    232           Observe(
    233               NotificationType(
    234               NotificationType::SYNC_CONFIGURE_BLOCKED),_,_))
    235           .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
    236 
    237       service_->RegisterDataTypeController(data_type_controller);
    238       service_->Initialize();
    239       MessageLoop::current()->Run();
    240       FlushLastDBTask();
    241 
    242       service_->SetPassphrase("foo", false, true);
    243       MessageLoop::current()->Run();
    244     }
    245   }
    246 
    247   void AddPasswordSyncNode(const PasswordForm& entry) {
    248     sync_api::WriteTransaction trans(service_->GetUserShare());
    249     sync_api::ReadNode password_root(&trans);
    250     ASSERT_TRUE(password_root.InitByTagLookup(browser_sync::kPasswordTag));
    251 
    252     sync_api::WriteNode node(&trans);
    253     std::string tag = PasswordModelAssociator::MakeTag(entry);
    254     ASSERT_TRUE(node.InitUniqueByCreation(syncable::PASSWORDS,
    255                                           password_root,
    256                                           tag));
    257     PasswordModelAssociator::WriteToSyncNode(entry, &node);
    258   }
    259 
    260   void GetPasswordEntriesFromSyncDB(std::vector<PasswordForm>* entries) {
    261     sync_api::ReadTransaction trans(service_->GetUserShare());
    262     sync_api::ReadNode password_root(&trans);
    263     ASSERT_TRUE(password_root.InitByTagLookup(browser_sync::kPasswordTag));
    264 
    265     int64 child_id = password_root.GetFirstChildId();
    266     while (child_id != sync_api::kInvalidId) {
    267       sync_api::ReadNode child_node(&trans);
    268       ASSERT_TRUE(child_node.InitByIdLookup(child_id));
    269 
    270       const sync_pb::PasswordSpecificsData& password =
    271           child_node.GetPasswordSpecifics();
    272 
    273       PasswordForm form;
    274       PasswordModelAssociator::CopyPassword(password, &form);
    275 
    276       entries->push_back(form);
    277 
    278       child_id = child_node.GetSuccessorId();
    279     }
    280   }
    281 
    282   bool ComparePasswords(const PasswordForm& lhs, const PasswordForm& rhs) {
    283     return lhs.scheme == rhs.scheme &&
    284            lhs.signon_realm == rhs.signon_realm &&
    285            lhs.origin == rhs.origin &&
    286            lhs.action == rhs.action &&
    287            lhs.username_element == rhs.username_element &&
    288            lhs.username_value == rhs.username_value &&
    289            lhs.password_element == rhs.password_element &&
    290            lhs.password_value == rhs.password_value &&
    291            lhs.ssl_valid == rhs.ssl_valid &&
    292            lhs.preferred == rhs.preferred &&
    293            lhs.date_created == rhs.date_created &&
    294            lhs.blacklisted_by_user == rhs.blacklisted_by_user;
    295   }
    296 
    297   void SetIdleChangeProcessorExpectations() {
    298     EXPECT_CALL(*password_store_, AddLoginImpl(_)).Times(0);
    299     EXPECT_CALL(*password_store_, UpdateLoginImpl(_)).Times(0);
    300     EXPECT_CALL(*password_store_, RemoveLoginImpl(_)).Times(0);
    301   }
    302 
    303   friend class AddPasswordEntriesTask;
    304 
    305   BrowserThread db_thread_;
    306   scoped_refptr<ThreadNotificationService> notification_service_;
    307   NotificationObserverMock observer_;
    308   ProfileMock profile_;
    309   scoped_refptr<MockPasswordStore> password_store_;
    310   NotificationRegistrar registrar_;
    311 };
    312 
    313 class AddPasswordEntriesTask : public Task {
    314  public:
    315   AddPasswordEntriesTask(ProfileSyncServicePasswordTest* test,
    316                          const std::vector<PasswordForm>& entries)
    317       : test_(test), entries_(entries) {
    318   }
    319 
    320   virtual void Run() {
    321     for (size_t i = 0; i < entries_.size(); ++i) {
    322       test_->AddPasswordSyncNode(entries_[i]);
    323     }
    324   }
    325 
    326  private:
    327   ProfileSyncServicePasswordTest* test_;
    328   const std::vector<PasswordForm>& entries_;
    329 };
    330 
    331 TEST_F(ProfileSyncServicePasswordTest, FailModelAssociation) {
    332   StartSyncService(NULL, NULL);
    333   EXPECT_TRUE(service_->unrecoverable_error_detected());
    334 }
    335 
    336 TEST_F(ProfileSyncServicePasswordTest, EmptyNativeEmptySync) {
    337   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    338       .WillOnce(Return(true));
    339   EXPECT_CALL(*password_store_, FillBlacklistLogins(_))
    340       .WillOnce(Return(true));
    341   SetIdleChangeProcessorExpectations();
    342   CreateRootTask task(this, syncable::PASSWORDS);
    343   StartSyncService(&task, NULL);
    344   std::vector<PasswordForm> sync_entries;
    345   GetPasswordEntriesFromSyncDB(&sync_entries);
    346   EXPECT_EQ(0U, sync_entries.size());
    347 }
    348 
    349 TEST_F(ProfileSyncServicePasswordTest, HasNativeEntriesEmptySync) {
    350   std::vector<PasswordForm*> forms;
    351   std::vector<PasswordForm> expected_forms;
    352   PasswordForm* new_form = new PasswordForm;
    353   new_form->scheme = PasswordForm::SCHEME_HTML;
    354   new_form->signon_realm = "pie";
    355   new_form->origin = GURL("http://pie.com");
    356   new_form->action = GURL("http://pie.com/submit");
    357   new_form->username_element = UTF8ToUTF16("name");
    358   new_form->username_value = UTF8ToUTF16("tom");
    359   new_form->password_element = UTF8ToUTF16("cork");
    360   new_form->password_value = UTF8ToUTF16("password1");
    361   new_form->ssl_valid = true;
    362   new_form->preferred = false;
    363   new_form->date_created = base::Time::FromInternalValue(1234);
    364   new_form->blacklisted_by_user = false;
    365   forms.push_back(new_form);
    366   expected_forms.push_back(*new_form);
    367   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    368       .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
    369   EXPECT_CALL(*password_store_, FillBlacklistLogins(_))
    370       .WillOnce(Return(true));
    371   SetIdleChangeProcessorExpectations();
    372   CreateRootTask task(this, syncable::PASSWORDS);
    373   StartSyncService(&task, NULL);
    374   std::vector<PasswordForm> sync_forms;
    375   GetPasswordEntriesFromSyncDB(&sync_forms);
    376   ASSERT_EQ(1U, sync_forms.size());
    377   EXPECT_TRUE(ComparePasswords(expected_forms[0], sync_forms[0]));
    378 }
    379 
    380 TEST_F(ProfileSyncServicePasswordTest, HasNativeEntriesEmptySyncSameUsername) {
    381   std::vector<PasswordForm*> forms;
    382   std::vector<PasswordForm> expected_forms;
    383 
    384   {
    385     PasswordForm* new_form = new PasswordForm;
    386     new_form->scheme = PasswordForm::SCHEME_HTML;
    387     new_form->signon_realm = "pie";
    388     new_form->origin = GURL("http://pie.com");
    389     new_form->action = GURL("http://pie.com/submit");
    390     new_form->username_element = UTF8ToUTF16("name");
    391     new_form->username_value = UTF8ToUTF16("tom");
    392     new_form->password_element = UTF8ToUTF16("cork");
    393     new_form->password_value = UTF8ToUTF16("password1");
    394     new_form->ssl_valid = true;
    395     new_form->preferred = false;
    396     new_form->date_created = base::Time::FromInternalValue(1234);
    397     new_form->blacklisted_by_user = false;
    398     forms.push_back(new_form);
    399     expected_forms.push_back(*new_form);
    400   }
    401   {
    402     PasswordForm* new_form = new PasswordForm;
    403     new_form->scheme = PasswordForm::SCHEME_HTML;
    404     new_form->signon_realm = "pie";
    405     new_form->origin = GURL("http://pie.com");
    406     new_form->action = GURL("http://pie.com/submit");
    407     new_form->username_element = UTF8ToUTF16("name");
    408     new_form->username_value = UTF8ToUTF16("pete");
    409     new_form->password_element = UTF8ToUTF16("cork");
    410     new_form->password_value = UTF8ToUTF16("password2");
    411     new_form->ssl_valid = true;
    412     new_form->preferred = false;
    413     new_form->date_created = base::Time::FromInternalValue(1234);
    414     new_form->blacklisted_by_user = false;
    415     forms.push_back(new_form);
    416     expected_forms.push_back(*new_form);
    417   }
    418 
    419   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    420       .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
    421   EXPECT_CALL(*password_store_, FillBlacklistLogins(_))
    422       .WillOnce(Return(true));
    423   SetIdleChangeProcessorExpectations();
    424   CreateRootTask task(this, syncable::PASSWORDS);
    425   StartSyncService(&task, NULL);
    426   std::vector<PasswordForm> sync_forms;
    427   GetPasswordEntriesFromSyncDB(&sync_forms);
    428   ASSERT_EQ(2U, sync_forms.size());
    429   EXPECT_TRUE(ComparePasswords(expected_forms[0], sync_forms[1]));
    430   EXPECT_TRUE(ComparePasswords(expected_forms[1], sync_forms[0]));
    431 }
    432 
    433 TEST_F(ProfileSyncServicePasswordTest, HasNativeHasSyncNoMerge) {
    434   std::vector<PasswordForm*> native_forms;
    435   std::vector<PasswordForm> sync_forms;
    436   std::vector<PasswordForm> expected_forms;
    437   {
    438     PasswordForm* new_form = new PasswordForm;
    439     new_form->scheme = PasswordForm::SCHEME_HTML;
    440     new_form->signon_realm = "pie";
    441     new_form->origin = GURL("http://pie.com");
    442     new_form->action = GURL("http://pie.com/submit");
    443     new_form->username_element = UTF8ToUTF16("name");
    444     new_form->username_value = UTF8ToUTF16("tom");
    445     new_form->password_element = UTF8ToUTF16("cork");
    446     new_form->password_value = UTF8ToUTF16("password1");
    447     new_form->ssl_valid = true;
    448     new_form->preferred = false;
    449     new_form->date_created = base::Time::FromInternalValue(1234);
    450     new_form->blacklisted_by_user = false;
    451 
    452     native_forms.push_back(new_form);
    453     expected_forms.push_back(*new_form);
    454   }
    455 
    456   {
    457     PasswordForm new_form;
    458     new_form.scheme = PasswordForm::SCHEME_HTML;
    459     new_form.signon_realm = "pie2";
    460     new_form.origin = GURL("http://pie2.com");
    461     new_form.action = GURL("http://pie2.com/submit");
    462     new_form.username_element = UTF8ToUTF16("name2");
    463     new_form.username_value = UTF8ToUTF16("tom2");
    464     new_form.password_element = UTF8ToUTF16("cork2");
    465     new_form.password_value = UTF8ToUTF16("password12");
    466     new_form.ssl_valid = false;
    467     new_form.preferred = true;
    468     new_form.date_created = base::Time::FromInternalValue(12345);
    469     new_form.blacklisted_by_user = false;
    470     sync_forms.push_back(new_form);
    471     expected_forms.push_back(new_form);
    472   }
    473 
    474   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    475       .WillOnce(DoAll(SetArgumentPointee<0>(native_forms), Return(true)));
    476   EXPECT_CALL(*password_store_, FillBlacklistLogins(_)).WillOnce(Return(true));
    477   EXPECT_CALL(*password_store_, AddLoginImpl(_)).Times(1);
    478 
    479   CreateRootTask root_task(this, syncable::PASSWORDS);
    480   AddPasswordEntriesTask node_task(this, sync_forms);
    481   StartSyncService(&root_task, &node_task);
    482 
    483   std::vector<PasswordForm> new_sync_forms;
    484   GetPasswordEntriesFromSyncDB(&new_sync_forms);
    485 
    486   EXPECT_EQ(2U, new_sync_forms.size());
    487   EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
    488   EXPECT_TRUE(ComparePasswords(expected_forms[1], new_sync_forms[1]));
    489 }
    490 
    491 // Same as HasNativeHasEmptyNoMerge, but we attempt to aquire a sync transaction
    492 // every time the password store is accessed.
    493 TEST_F(ProfileSyncServicePasswordTest, EnsureNoTransactions) {
    494   std::vector<PasswordForm*> native_forms;
    495   std::vector<PasswordForm> sync_forms;
    496   std::vector<PasswordForm> expected_forms;
    497   {
    498     PasswordForm* new_form = new PasswordForm;
    499     new_form->scheme = PasswordForm::SCHEME_HTML;
    500     new_form->signon_realm = "pie";
    501     new_form->origin = GURL("http://pie.com");
    502     new_form->action = GURL("http://pie.com/submit");
    503     new_form->username_element = UTF8ToUTF16("name");
    504     new_form->username_value = UTF8ToUTF16("tom");
    505     new_form->password_element = UTF8ToUTF16("cork");
    506     new_form->password_value = UTF8ToUTF16("password1");
    507     new_form->ssl_valid = true;
    508     new_form->preferred = false;
    509     new_form->date_created = base::Time::FromInternalValue(1234);
    510     new_form->blacklisted_by_user = false;
    511 
    512     native_forms.push_back(new_form);
    513     expected_forms.push_back(*new_form);
    514   }
    515 
    516   {
    517     PasswordForm new_form;
    518     new_form.scheme = PasswordForm::SCHEME_HTML;
    519     new_form.signon_realm = "pie2";
    520     new_form.origin = GURL("http://pie2.com");
    521     new_form.action = GURL("http://pie2.com/submit");
    522     new_form.username_element = UTF8ToUTF16("name2");
    523     new_form.username_value = UTF8ToUTF16("tom2");
    524     new_form.password_element = UTF8ToUTF16("cork2");
    525     new_form.password_value = UTF8ToUTF16("password12");
    526     new_form.ssl_valid = false;
    527     new_form.preferred = true;
    528     new_form.date_created = base::Time::FromInternalValue(12345);
    529     new_form.blacklisted_by_user = false;
    530     sync_forms.push_back(new_form);
    531     expected_forms.push_back(new_form);
    532   }
    533 
    534   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    535       .WillOnce(DoAll(SetArgumentPointee<0>(native_forms),
    536                       AcquireSyncTransaction(this),
    537                       Return(true)));
    538   EXPECT_CALL(*password_store_, FillBlacklistLogins(_))
    539       .WillOnce(DoAll(AcquireSyncTransaction(this),
    540                       Return(true)));
    541   EXPECT_CALL(*password_store_, AddLoginImpl(_))
    542       .WillOnce(AcquireSyncTransaction(this));
    543 
    544   CreateRootTask root_task(this, syncable::PASSWORDS);
    545   AddPasswordEntriesTask node_task(this, sync_forms);
    546   StartSyncService(&root_task, &node_task);
    547 
    548   std::vector<PasswordForm> new_sync_forms;
    549   GetPasswordEntriesFromSyncDB(&new_sync_forms);
    550 
    551   EXPECT_EQ(2U, new_sync_forms.size());
    552   EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
    553   EXPECT_TRUE(ComparePasswords(expected_forms[1], new_sync_forms[1]));
    554 }
    555 
    556 TEST_F(ProfileSyncServicePasswordTest, HasNativeHasSyncMergeEntry) {
    557   std::vector<PasswordForm*> native_forms;
    558   std::vector<PasswordForm> sync_forms;
    559   std::vector<PasswordForm> expected_forms;
    560   {
    561     PasswordForm* new_form = new PasswordForm;
    562     new_form->scheme = PasswordForm::SCHEME_HTML;
    563     new_form->signon_realm = "pie";
    564     new_form->origin = GURL("http://pie.com");
    565     new_form->action = GURL("http://pie.com/submit");
    566     new_form->username_element = UTF8ToUTF16("name");
    567     new_form->username_value = UTF8ToUTF16("tom");
    568     new_form->password_element = UTF8ToUTF16("cork");
    569     new_form->password_value = UTF8ToUTF16("password1");
    570     new_form->ssl_valid = true;
    571     new_form->preferred = false;
    572     new_form->date_created = base::Time::FromInternalValue(1234);
    573     new_form->blacklisted_by_user = false;
    574 
    575     native_forms.push_back(new_form);
    576   }
    577 
    578   {
    579     PasswordForm new_form;
    580     new_form.scheme = PasswordForm::SCHEME_HTML;
    581     new_form.signon_realm = "pie";
    582     new_form.origin = GURL("http://pie.com");
    583     new_form.action = GURL("http://pie.com/submit");
    584     new_form.username_element = UTF8ToUTF16("name");
    585     new_form.username_value = UTF8ToUTF16("tom");
    586     new_form.password_element = UTF8ToUTF16("cork");
    587     new_form.password_value = UTF8ToUTF16("password12");
    588     new_form.ssl_valid = false;
    589     new_form.preferred = true;
    590     new_form.date_created = base::Time::FromInternalValue(12345);
    591     new_form.blacklisted_by_user = false;
    592     sync_forms.push_back(new_form);
    593   }
    594 
    595   {
    596     PasswordForm new_form;
    597     new_form.scheme = PasswordForm::SCHEME_HTML;
    598     new_form.signon_realm = "pie";
    599     new_form.origin = GURL("http://pie.com");
    600     new_form.action = GURL("http://pie.com/submit");
    601     new_form.username_element = UTF8ToUTF16("name");
    602     new_form.username_value = UTF8ToUTF16("tom");
    603     new_form.password_element = UTF8ToUTF16("cork");
    604     new_form.password_value = UTF8ToUTF16("password12");
    605     new_form.ssl_valid = false;
    606     new_form.preferred = true;
    607     new_form.date_created = base::Time::FromInternalValue(12345);
    608     new_form.blacklisted_by_user = false;
    609     expected_forms.push_back(new_form);
    610   }
    611 
    612   EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
    613       .WillOnce(DoAll(SetArgumentPointee<0>(native_forms), Return(true)));
    614   EXPECT_CALL(*password_store_, FillBlacklistLogins(_)).WillOnce(Return(true));
    615   EXPECT_CALL(*password_store_, UpdateLoginImpl(_)).Times(1);
    616 
    617   CreateRootTask root_task(this, syncable::PASSWORDS);
    618   AddPasswordEntriesTask node_task(this, sync_forms);
    619 
    620   StartSyncService(&root_task, &node_task);
    621 
    622   std::vector<PasswordForm> new_sync_forms;
    623   GetPasswordEntriesFromSyncDB(&new_sync_forms);
    624 
    625   EXPECT_EQ(1U, new_sync_forms.size());
    626   EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
    627 }
    628