• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ACTION_P3(MakePasswordSyncComponents,service,ps,dtc)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 
ACTION_P(AcquireSyncTransaction,password_test_service)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 
QuitMessageLoop()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:
PasswordTestProfileSyncService(ProfileSyncFactory * factory,Profile * profile,const std::string & test_user,bool synchronous_backend_initialization,Task * initial_condition_setup_task,Task * passphrase_accept_task)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 
~PasswordTestProfileSyncService()132   virtual ~PasswordTestProfileSyncService() {}
133 
OnPassphraseAccepted()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:
GetUserShare()148   sync_api::UserShare* GetUserShare() {
149     return service_->GetUserShare();
150   }
151  protected:
ProfileSyncServicePasswordTest()152   ProfileSyncServicePasswordTest()
153       : db_thread_(BrowserThread::DB) {
154   }
155 
SetUp()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 
TearDown()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 
SignalEvent(base::WaitableEvent * done)185   static void SignalEvent(base::WaitableEvent* done) {
186     done->Signal();
187   }
188 
FlushLastDBTask()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 
StartSyncService(Task * root_task,Task * node_task)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 
AddPasswordSyncNode(const PasswordForm & entry)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 
GetPasswordEntriesFromSyncDB(std::vector<PasswordForm> * entries)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 
ComparePasswords(const PasswordForm & lhs,const PasswordForm & rhs)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 
SetIdleChangeProcessorExpectations()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:
AddPasswordEntriesTask(ProfileSyncServicePasswordTest * test,const std::vector<PasswordForm> & entries)315   AddPasswordEntriesTask(ProfileSyncServicePasswordTest* test,
316                          const std::vector<PasswordForm>& entries)
317       : test_(test), entries_(entries) {
318   }
319 
Run()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 
TEST_F(ProfileSyncServicePasswordTest,FailModelAssociation)331 TEST_F(ProfileSyncServicePasswordTest, FailModelAssociation) {
332   StartSyncService(NULL, NULL);
333   EXPECT_TRUE(service_->unrecoverable_error_detected());
334 }
335 
TEST_F(ProfileSyncServicePasswordTest,EmptyNativeEmptySync)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 
TEST_F(ProfileSyncServicePasswordTest,HasNativeEntriesEmptySync)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 
TEST_F(ProfileSyncServicePasswordTest,HasNativeEntriesEmptySyncSameUsername)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 
TEST_F(ProfileSyncServicePasswordTest,HasNativeHasSyncNoMerge)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.
TEST_F(ProfileSyncServicePasswordTest,EnsureNoTransactions)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 
TEST_F(ProfileSyncServicePasswordTest,HasNativeHasSyncMergeEntry)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