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
40using base::Time;
41using browser_sync::PasswordChangeProcessor;
42using browser_sync::PasswordDataTypeController;
43using browser_sync::PasswordModelAssociator;
44using browser_sync::TestIdFactory;
45using browser_sync::UnrecoverableErrorHandler;
46using sync_api::SyncManager;
47using sync_api::UserShare;
48using syncable::BASE_VERSION;
49using syncable::CREATE;
50using syncable::DirectoryManager;
51using syncable::IS_DEL;
52using syncable::IS_DIR;
53using syncable::IS_UNAPPLIED_UPDATE;
54using syncable::IS_UNSYNCED;
55using syncable::MutableEntry;
56using syncable::SERVER_IS_DIR;
57using syncable::SERVER_VERSION;
58using syncable::SPECIFICS;
59using syncable::ScopedDirLookup;
60using syncable::UNIQUE_SERVER_TAG;
61using syncable::UNITTEST;
62using syncable::WriteTransaction;
63using testing::_;
64using testing::AtLeast;
65using testing::DoAll;
66using testing::DoDefault;
67using testing::ElementsAre;
68using testing::Eq;
69using testing::Invoke;
70using testing::InvokeWithoutArgs;
71using testing::Return;
72using testing::SaveArg;
73using testing::SetArgumentPointee;
74using webkit_glue::PasswordForm;
75
76ACTION_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
86ACTION_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
93static void QuitMessageLoop() {
94  MessageLoop::current()->Quit();
95}
96
97class 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
119class 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
146class 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
313class 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
331TEST_F(ProfileSyncServicePasswordTest, FailModelAssociation) {
332  StartSyncService(NULL, NULL);
333  EXPECT_TRUE(service_->unrecoverable_error_detected());
334}
335
336TEST_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
349TEST_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
380TEST_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
433TEST_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.
493TEST_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
556TEST_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