1// Copyright (c) 2012 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/bind.h"
10#include "base/location.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/test/test_timeouts.h"
15#include "base/time/time.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/invalidation/invalidation_service_factory.h"
18#include "chrome/browser/password_manager/mock_password_store.h"
19#include "chrome/browser/password_manager/password_store.h"
20#include "chrome/browser/password_manager/password_store_factory.h"
21#include "chrome/browser/signin/profile_oauth2_token_service.h"
22#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
23#include "chrome/browser/signin/signin_manager.h"
24#include "chrome/browser/signin/signin_manager_factory.h"
25#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
26#include "chrome/browser/sync/fake_oauth2_token_service.h"
27#include "chrome/browser/sync/glue/password_change_processor.h"
28#include "chrome/browser/sync/glue/password_data_type_controller.h"
29#include "chrome/browser/sync/glue/password_model_associator.h"
30#include "chrome/browser/sync/profile_sync_components_factory.h"
31#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
32#include "chrome/browser/sync/profile_sync_service.h"
33#include "chrome/browser/sync/profile_sync_service_factory.h"
34#include "chrome/browser/sync/profile_sync_test_util.h"
35#include "chrome/browser/sync/test_profile_sync_service.h"
36#include "chrome/common/pref_names.h"
37#include "chrome/test/base/testing_profile.h"
38#include "components/autofill/core/common/password_form.h"
39#include "content/public/browser/notification_source.h"
40#include "content/public/test/mock_notification_observer.h"
41#include "content/public/test/test_browser_thread.h"
42#include "google_apis/gaia/gaia_constants.h"
43#include "sync/internal_api/public/read_node.h"
44#include "sync/internal_api/public/read_transaction.h"
45#include "sync/internal_api/public/write_node.h"
46#include "sync/internal_api/public/write_transaction.h"
47#include "sync/protocol/password_specifics.pb.h"
48#include "sync/test/engine/test_id_factory.h"
49#include "testing/gmock/include/gmock/gmock.h"
50
51using autofill::PasswordForm;
52using base::Time;
53using browser_sync::PasswordChangeProcessor;
54using browser_sync::PasswordDataTypeController;
55using browser_sync::PasswordModelAssociator;
56using content::BrowserThread;
57using syncer::syncable::WriteTransaction;
58using testing::_;
59using testing::AtLeast;
60using testing::DoAll;
61using testing::InvokeWithoutArgs;
62using testing::Return;
63using testing::SetArgumentPointee;
64
65ACTION_P3(MakePasswordSyncComponents, service, ps, dtc) {
66  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
67  PasswordModelAssociator* model_associator =
68      new PasswordModelAssociator(service, ps, NULL);
69  PasswordChangeProcessor* change_processor =
70      new PasswordChangeProcessor(model_associator, ps, dtc);
71  return ProfileSyncComponentsFactory::SyncComponents(model_associator,
72                                                      change_processor);
73}
74
75ACTION_P(AcquireSyncTransaction, password_test_service) {
76  // Check to make sure we can aquire a transaction (will crash if a transaction
77  // is already held by this thread, deadlock if held by another thread).
78  syncer::WriteTransaction trans(
79      FROM_HERE, password_test_service->GetUserShare());
80  DVLOG(1) << "Sync transaction acquired.";
81}
82
83class NullPasswordStore : public MockPasswordStore {
84 public:
85  NullPasswordStore() {}
86
87  static scoped_refptr<RefcountedBrowserContextKeyedService> Build(
88      content::BrowserContext* profile) {
89    return scoped_refptr<RefcountedBrowserContextKeyedService>();
90  }
91
92 protected:
93  virtual ~NullPasswordStore() {}
94};
95
96class PasswordTestProfileSyncService : public TestProfileSyncService {
97 public:
98  PasswordTestProfileSyncService(
99      ProfileSyncComponentsFactory* factory,
100      Profile* profile,
101      SigninManagerBase* signin,
102      ProfileOAuth2TokenService* oauth2_token_service)
103      : TestProfileSyncService(factory,
104                               profile,
105                               signin,
106                               oauth2_token_service,
107                               ProfileSyncService::AUTO_START) {}
108
109  virtual ~PasswordTestProfileSyncService() {}
110
111  virtual void OnPassphraseAccepted() OVERRIDE {
112    if (!callback_.is_null())
113      callback_.Run();
114
115    TestProfileSyncService::OnPassphraseAccepted();
116  }
117
118  static BrowserContextKeyedService* Build(content::BrowserContext* context) {
119    Profile* profile = static_cast<Profile*>(context);
120    SigninManagerBase* signin =
121        SigninManagerFactory::GetForProfile(profile);
122    ProfileOAuth2TokenService* oauth2_token_service =
123        ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
124    ProfileSyncComponentsFactoryMock* factory =
125        new ProfileSyncComponentsFactoryMock();
126    return new PasswordTestProfileSyncService(
127        factory, profile, signin, oauth2_token_service);
128  }
129
130  void set_passphrase_accept_callback(const base::Closure& callback) {
131    callback_ = callback;
132  }
133
134 private:
135  base::Closure callback_;
136};
137
138class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
139 public:
140  syncer::UserShare* GetUserShare() {
141    return sync_service_->GetUserShare();
142  }
143
144  void AddPasswordSyncNode(const PasswordForm& entry) {
145    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
146    syncer::ReadNode password_root(&trans);
147    ASSERT_EQ(syncer::BaseNode::INIT_OK,
148              password_root.InitByTagLookup(browser_sync::kPasswordTag));
149
150    syncer::WriteNode node(&trans);
151    std::string tag = PasswordModelAssociator::MakeTag(entry);
152    syncer::WriteNode::InitUniqueByCreationResult result =
153        node.InitUniqueByCreation(syncer::PASSWORDS, password_root, tag);
154    ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
155    PasswordModelAssociator::WriteToSyncNode(entry, &node);
156  }
157
158 protected:
159  ProfileSyncServicePasswordTest() {}
160
161  virtual void SetUp() {
162    AbstractProfileSyncServiceTest::SetUp();
163    TestingProfile::Builder builder;
164    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
165                              FakeOAuth2TokenService::BuildTokenService);
166    profile_ = builder.Build().Pass();
167    invalidation::InvalidationServiceFactory::GetInstance()->
168        SetBuildOnlyFakeInvalidatorsForTest(true);
169    password_store_ = static_cast<MockPasswordStore*>(
170        PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
171            profile_.get(), MockPasswordStore::Build).get());
172  }
173
174  virtual void TearDown() {
175    if (password_store_.get())
176      password_store_->ShutdownOnUIThread();
177      ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
178          profile_.get(), NULL);
179      profile_.reset();
180      AbstractProfileSyncServiceTest::TearDown();
181  }
182
183  static void SignalEvent(base::WaitableEvent* done) {
184    done->Signal();
185  }
186
187  void FlushLastDBTask() {
188    base::WaitableEvent done(false, false);
189    BrowserThread::PostTask(
190        BrowserThread::DB, FROM_HERE,
191        base::Bind(&ProfileSyncServicePasswordTest::SignalEvent, &done));
192    done.TimedWait(TestTimeouts::action_timeout());
193  }
194
195  void StartSyncService(const base::Closure& root_callback,
196                        const base::Closure& node_callback) {
197    if (!sync_service_) {
198      SigninManagerBase* signin =
199          SigninManagerFactory::GetForProfile(profile_.get());
200      signin->SetAuthenticatedUsername("test_user@gmail.com");
201
202      PasswordTestProfileSyncService* sync =
203          static_cast<PasswordTestProfileSyncService*>(
204              ProfileSyncServiceFactory::GetInstance()->
205                  SetTestingFactoryAndUse(profile_.get(),
206                      &PasswordTestProfileSyncService::Build));
207      sync->set_backend_init_callback(root_callback);
208      sync->set_passphrase_accept_callback(node_callback);
209      sync_service_ = sync;
210
211      syncer::ModelTypeSet preferred_types =
212          sync_service_->GetPreferredDataTypes();
213      preferred_types.Put(syncer::PASSWORDS);
214      sync_service_->ChangePreferredDataTypes(preferred_types);
215      PasswordDataTypeController* data_type_controller =
216          new PasswordDataTypeController(sync_service_->factory(),
217                                         profile_.get(),
218                                         sync_service_);
219      ProfileSyncComponentsFactoryMock* components =
220          sync_service_->components_factory_mock();
221      if (password_store_.get()) {
222        EXPECT_CALL(*components, CreatePasswordSyncComponents(_, _, _))
223            .Times(AtLeast(1)).  // Can be more if we hit NEEDS_CRYPTO.
224            WillRepeatedly(MakePasswordSyncComponents(
225                sync_service_, password_store_.get(), data_type_controller));
226      } else {
227        // When the password store is unavailable, password sync components must
228        // not be created.
229        EXPECT_CALL(*components, CreatePasswordSyncComponents(_, _, _))
230            .Times(0);
231      }
232      EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _, _)).
233          WillOnce(ReturnNewDataTypeManager());
234
235      // We need tokens to get the tests going
236      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
237          ->UpdateCredentials("test_user@gmail.com", "oauth2_login_token");
238
239      sync_service_->RegisterDataTypeController(data_type_controller);
240      sync_service_->Initialize();
241      base::MessageLoop::current()->Run();
242      FlushLastDBTask();
243
244      sync_service_->SetEncryptionPassphrase("foo",
245                                             ProfileSyncService::IMPLICIT);
246      base::MessageLoop::current()->Run();
247    }
248  }
249
250  // Helper to sort the results of GetPasswordEntriesFromSyncDB.  The sorting
251  // doesn't need to be particularly intelligent, it just needs to be consistent
252  // enough that we can base our tests expectations on the ordering it provides.
253  static bool PasswordFormComparator(const PasswordForm& pf1,
254                                     const PasswordForm& pf2) {
255    if (pf1.submit_element < pf2.submit_element)
256      return true;
257    if (pf1.username_element < pf2.username_element)
258      return true;
259    if (pf1.username_value < pf2.username_value)
260      return true;
261    if (pf1.password_element < pf2.password_element)
262      return true;
263    if (pf1.password_value < pf2.password_value)
264      return true;
265
266    return false;
267  }
268
269  void GetPasswordEntriesFromSyncDB(std::vector<PasswordForm>* entries) {
270    syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
271    syncer::ReadNode password_root(&trans);
272    ASSERT_EQ(syncer::BaseNode::INIT_OK,
273              password_root.InitByTagLookup(browser_sync::kPasswordTag));
274
275    int64 child_id = password_root.GetFirstChildId();
276    while (child_id != syncer::kInvalidId) {
277      syncer::ReadNode child_node(&trans);
278      ASSERT_EQ(syncer::BaseNode::INIT_OK,
279                child_node.InitByIdLookup(child_id));
280
281      const sync_pb::PasswordSpecificsData& password =
282          child_node.GetPasswordSpecifics();
283
284      PasswordForm form;
285      PasswordModelAssociator::CopyPassword(password, &form);
286
287      entries->push_back(form);
288
289      child_id = child_node.GetSuccessorId();
290    }
291
292    std::sort(entries->begin(), entries->end(), PasswordFormComparator);
293  }
294
295  bool ComparePasswords(const PasswordForm& lhs, const PasswordForm& rhs) {
296    return lhs.scheme == rhs.scheme &&
297           lhs.signon_realm == rhs.signon_realm &&
298           lhs.origin == rhs.origin &&
299           lhs.action == rhs.action &&
300           lhs.username_element == rhs.username_element &&
301           lhs.username_value == rhs.username_value &&
302           lhs.password_element == rhs.password_element &&
303           lhs.password_value == rhs.password_value &&
304           lhs.ssl_valid == rhs.ssl_valid &&
305           lhs.preferred == rhs.preferred &&
306           lhs.date_created == rhs.date_created &&
307           lhs.blacklisted_by_user == rhs.blacklisted_by_user;
308  }
309
310  void SetIdleChangeProcessorExpectations() {
311    EXPECT_CALL(*password_store_.get(), AddLoginImpl(_)).Times(0);
312    EXPECT_CALL(*password_store_.get(), UpdateLoginImpl(_)).Times(0);
313    EXPECT_CALL(*password_store_.get(), RemoveLoginImpl(_)).Times(0);
314  }
315
316  content::MockNotificationObserver observer_;
317  scoped_ptr<TestingProfile> profile_;
318  scoped_refptr<MockPasswordStore> password_store_;
319  content::NotificationRegistrar registrar_;
320};
321
322void AddPasswordEntriesCallback(ProfileSyncServicePasswordTest* test,
323                                const std::vector<PasswordForm>& entries) {
324  for (size_t i = 0; i < entries.size(); ++i)
325    test->AddPasswordSyncNode(entries[i]);
326}
327
328// Flaky on mac_rel. See http://crbug.com/228943
329#if defined(OS_MACOSX)
330#define MAYBE_EmptyNativeEmptySync DISABLED_EmptyNativeEmptySync
331#define MAYBE_EnsureNoTransactions DISABLED_EnsureNoTransactions
332#define MAYBE_FailModelAssociation DISABLED_FailModelAssociation
333#define MAYBE_FailPasswordStoreLoad DISABLED_FailPasswordStoreLoad
334#define MAYBE_HasNativeEntriesEmptySync DISABLED_HasNativeEntriesEmptySync
335#define MAYBE_HasNativeEntriesEmptySyncSameUsername \
336    DISABLED_HasNativeEntriesEmptySyncSameUsername
337#define MAYBE_HasNativeHasSyncMergeEntry DISABLED_HasNativeHasSyncMergeEntry
338#define MAYBE_HasNativeHasSyncNoMerge DISABLED_HasNativeHasSyncNoMerge
339#else
340#define MAYBE_EmptyNativeEmptySync EmptyNativeEmptySync
341#define MAYBE_EnsureNoTransactions EnsureNoTransactions
342#define MAYBE_FailModelAssociation FailModelAssociation
343#define MAYBE_FailPasswordStoreLoad FailPasswordStoreLoad
344#define MAYBE_HasNativeEntriesEmptySync HasNativeEntriesEmptySync
345#define MAYBE_HasNativeEntriesEmptySyncSameUsername \
346    HasNativeEntriesEmptySyncSameUsername
347#define MAYBE_HasNativeHasSyncMergeEntry HasNativeHasSyncMergeEntry
348#define MAYBE_HasNativeHasSyncNoMerge HasNativeHasSyncNoMerge
349#endif
350
351TEST_F(ProfileSyncServicePasswordTest, MAYBE_FailModelAssociation) {
352  StartSyncService(base::Closure(), base::Closure());
353  EXPECT_TRUE(sync_service_->HasUnrecoverableError());
354}
355
356TEST_F(ProfileSyncServicePasswordTest, MAYBE_FailPasswordStoreLoad) {
357  password_store_ = static_cast<NullPasswordStore*>(
358      PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
359          profile_.get(), NullPasswordStore::Build).get());
360  StartSyncService(base::Closure(), base::Closure());
361  EXPECT_FALSE(sync_service_->HasUnrecoverableError());
362  syncer::ModelTypeSet failed_types =
363      sync_service_->failed_data_types_handler().GetFailedTypes();
364  EXPECT_TRUE(failed_types.Equals(syncer::ModelTypeSet(syncer::PASSWORDS)));
365}
366
367TEST_F(ProfileSyncServicePasswordTest, MAYBE_EmptyNativeEmptySync) {
368  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
369      .WillOnce(Return(true));
370  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
371      .WillOnce(Return(true));
372  SetIdleChangeProcessorExpectations();
373  CreateRootHelper create_root(this, syncer::PASSWORDS);
374  StartSyncService(create_root.callback(), base::Closure());
375  std::vector<PasswordForm> sync_entries;
376  GetPasswordEntriesFromSyncDB(&sync_entries);
377  EXPECT_EQ(0U, sync_entries.size());
378}
379
380TEST_F(ProfileSyncServicePasswordTest, MAYBE_HasNativeEntriesEmptySync) {
381  std::vector<PasswordForm*> forms;
382  std::vector<PasswordForm> expected_forms;
383  PasswordForm* new_form = new PasswordForm;
384  new_form->scheme = PasswordForm::SCHEME_HTML;
385  new_form->signon_realm = "pie";
386  new_form->origin = GURL("http://pie.com");
387  new_form->action = GURL("http://pie.com/submit");
388  new_form->username_element = UTF8ToUTF16("name");
389  new_form->username_value = UTF8ToUTF16("tom");
390  new_form->password_element = UTF8ToUTF16("cork");
391  new_form->password_value = UTF8ToUTF16("password1");
392  new_form->ssl_valid = true;
393  new_form->preferred = false;
394  new_form->date_created = base::Time::FromInternalValue(1234);
395  new_form->blacklisted_by_user = false;
396  forms.push_back(new_form);
397  expected_forms.push_back(*new_form);
398  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
399      .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
400  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
401      .WillOnce(Return(true));
402  SetIdleChangeProcessorExpectations();
403  CreateRootHelper create_root(this, syncer::PASSWORDS);
404  StartSyncService(create_root.callback(), base::Closure());
405  std::vector<PasswordForm> sync_forms;
406  GetPasswordEntriesFromSyncDB(&sync_forms);
407  ASSERT_EQ(1U, sync_forms.size());
408  EXPECT_TRUE(ComparePasswords(expected_forms[0], sync_forms[0]));
409}
410
411TEST_F(ProfileSyncServicePasswordTest,
412       MAYBE_HasNativeEntriesEmptySyncSameUsername) {
413  std::vector<PasswordForm*> forms;
414  std::vector<PasswordForm> expected_forms;
415
416  {
417    PasswordForm* new_form = new PasswordForm;
418    new_form->scheme = PasswordForm::SCHEME_HTML;
419    new_form->signon_realm = "pie";
420    new_form->origin = GURL("http://pie.com");
421    new_form->action = GURL("http://pie.com/submit");
422    new_form->username_element = UTF8ToUTF16("name");
423    new_form->username_value = UTF8ToUTF16("tom");
424    new_form->password_element = UTF8ToUTF16("cork");
425    new_form->password_value = UTF8ToUTF16("password1");
426    new_form->ssl_valid = true;
427    new_form->preferred = false;
428    new_form->date_created = base::Time::FromInternalValue(1234);
429    new_form->blacklisted_by_user = false;
430    forms.push_back(new_form);
431    expected_forms.push_back(*new_form);
432  }
433  {
434    PasswordForm* new_form = new PasswordForm;
435    new_form->scheme = PasswordForm::SCHEME_HTML;
436    new_form->signon_realm = "pie";
437    new_form->origin = GURL("http://pie.com");
438    new_form->action = GURL("http://pie.com/submit");
439    new_form->username_element = UTF8ToUTF16("name");
440    new_form->username_value = UTF8ToUTF16("pete");
441    new_form->password_element = UTF8ToUTF16("cork");
442    new_form->password_value = UTF8ToUTF16("password2");
443    new_form->ssl_valid = true;
444    new_form->preferred = false;
445    new_form->date_created = base::Time::FromInternalValue(1234);
446    new_form->blacklisted_by_user = false;
447    forms.push_back(new_form);
448    expected_forms.push_back(*new_form);
449  }
450
451  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
452      .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
453  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
454      .WillOnce(Return(true));
455  SetIdleChangeProcessorExpectations();
456  CreateRootHelper create_root(this, syncer::PASSWORDS);
457  StartSyncService(create_root.callback(), base::Closure());
458  std::vector<PasswordForm> sync_forms;
459  GetPasswordEntriesFromSyncDB(&sync_forms);
460  ASSERT_EQ(2U, sync_forms.size());
461  EXPECT_TRUE(ComparePasswords(expected_forms[0], sync_forms[1]));
462  EXPECT_TRUE(ComparePasswords(expected_forms[1], sync_forms[0]));
463}
464
465TEST_F(ProfileSyncServicePasswordTest, MAYBE_HasNativeHasSyncNoMerge) {
466  std::vector<PasswordForm*> native_forms;
467  std::vector<PasswordForm> sync_forms;
468  std::vector<PasswordForm> expected_forms;
469  {
470    PasswordForm* new_form = new PasswordForm;
471    new_form->scheme = PasswordForm::SCHEME_HTML;
472    new_form->signon_realm = "pie";
473    new_form->origin = GURL("http://pie.com");
474    new_form->action = GURL("http://pie.com/submit");
475    new_form->username_element = UTF8ToUTF16("name");
476    new_form->username_value = UTF8ToUTF16("tom");
477    new_form->password_element = UTF8ToUTF16("cork");
478    new_form->password_value = UTF8ToUTF16("password1");
479    new_form->ssl_valid = true;
480    new_form->preferred = false;
481    new_form->date_created = base::Time::FromInternalValue(1234);
482    new_form->blacklisted_by_user = false;
483
484    native_forms.push_back(new_form);
485    expected_forms.push_back(*new_form);
486  }
487
488  {
489    PasswordForm new_form;
490    new_form.scheme = PasswordForm::SCHEME_HTML;
491    new_form.signon_realm = "pie2";
492    new_form.origin = GURL("http://pie2.com");
493    new_form.action = GURL("http://pie2.com/submit");
494    new_form.username_element = UTF8ToUTF16("name2");
495    new_form.username_value = UTF8ToUTF16("tom2");
496    new_form.password_element = UTF8ToUTF16("cork2");
497    new_form.password_value = UTF8ToUTF16("password12");
498    new_form.ssl_valid = false;
499    new_form.preferred = true;
500    new_form.date_created = base::Time::FromInternalValue(12345);
501    new_form.blacklisted_by_user = false;
502    sync_forms.push_back(new_form);
503    expected_forms.push_back(new_form);
504  }
505
506  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
507      .WillOnce(DoAll(SetArgumentPointee<0>(native_forms), Return(true)));
508  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
509      .WillOnce(Return(true));
510  EXPECT_CALL(*password_store_.get(), AddLoginImpl(_)).Times(1);
511
512  CreateRootHelper create_root(this, syncer::PASSWORDS);
513  StartSyncService(create_root.callback(),
514                   base::Bind(&AddPasswordEntriesCallback, this, sync_forms));
515
516  std::vector<PasswordForm> new_sync_forms;
517  GetPasswordEntriesFromSyncDB(&new_sync_forms);
518
519  EXPECT_EQ(2U, new_sync_forms.size());
520  EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
521  EXPECT_TRUE(ComparePasswords(expected_forms[1], new_sync_forms[1]));
522}
523
524// Same as HasNativeHasEmptyNoMerge, but we attempt to aquire a sync transaction
525// every time the password store is accessed.
526TEST_F(ProfileSyncServicePasswordTest, MAYBE_EnsureNoTransactions) {
527  std::vector<PasswordForm*> native_forms;
528  std::vector<PasswordForm> sync_forms;
529  std::vector<PasswordForm> expected_forms;
530  {
531    PasswordForm* new_form = new PasswordForm;
532    new_form->scheme = PasswordForm::SCHEME_HTML;
533    new_form->signon_realm = "pie";
534    new_form->origin = GURL("http://pie.com");
535    new_form->action = GURL("http://pie.com/submit");
536    new_form->username_element = UTF8ToUTF16("name");
537    new_form->username_value = UTF8ToUTF16("tom");
538    new_form->password_element = UTF8ToUTF16("cork");
539    new_form->password_value = UTF8ToUTF16("password1");
540    new_form->ssl_valid = true;
541    new_form->preferred = false;
542    new_form->date_created = base::Time::FromInternalValue(1234);
543    new_form->blacklisted_by_user = false;
544
545    native_forms.push_back(new_form);
546    expected_forms.push_back(*new_form);
547  }
548
549  {
550    PasswordForm new_form;
551    new_form.scheme = PasswordForm::SCHEME_HTML;
552    new_form.signon_realm = "pie2";
553    new_form.origin = GURL("http://pie2.com");
554    new_form.action = GURL("http://pie2.com/submit");
555    new_form.username_element = UTF8ToUTF16("name2");
556    new_form.username_value = UTF8ToUTF16("tom2");
557    new_form.password_element = UTF8ToUTF16("cork2");
558    new_form.password_value = UTF8ToUTF16("password12");
559    new_form.ssl_valid = false;
560    new_form.preferred = true;
561    new_form.date_created = base::Time::FromInternalValue(12345);
562    new_form.blacklisted_by_user = false;
563    sync_forms.push_back(new_form);
564    expected_forms.push_back(new_form);
565  }
566
567  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
568      .WillOnce(DoAll(SetArgumentPointee<0>(native_forms),
569                      AcquireSyncTransaction(this),
570                      Return(true)));
571  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
572      .WillOnce(DoAll(AcquireSyncTransaction(this), Return(true)));
573  EXPECT_CALL(*password_store_.get(), AddLoginImpl(_))
574      .WillOnce(AcquireSyncTransaction(this));
575
576  CreateRootHelper create_root(this, syncer::PASSWORDS);
577  StartSyncService(create_root.callback(),
578                   base::Bind(&AddPasswordEntriesCallback, this, sync_forms));
579
580  std::vector<PasswordForm> new_sync_forms;
581  GetPasswordEntriesFromSyncDB(&new_sync_forms);
582
583  EXPECT_EQ(2U, new_sync_forms.size());
584  EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
585  EXPECT_TRUE(ComparePasswords(expected_forms[1], new_sync_forms[1]));
586}
587
588TEST_F(ProfileSyncServicePasswordTest, MAYBE_HasNativeHasSyncMergeEntry) {
589  std::vector<PasswordForm*> native_forms;
590  std::vector<PasswordForm> sync_forms;
591  std::vector<PasswordForm> expected_forms;
592  {
593    PasswordForm* new_form = new PasswordForm;
594    new_form->scheme = PasswordForm::SCHEME_HTML;
595    new_form->signon_realm = "pie";
596    new_form->origin = GURL("http://pie.com");
597    new_form->action = GURL("http://pie.com/submit");
598    new_form->username_element = UTF8ToUTF16("name");
599    new_form->username_value = UTF8ToUTF16("tom");
600    new_form->password_element = UTF8ToUTF16("cork");
601    new_form->password_value = UTF8ToUTF16("password1");
602    new_form->ssl_valid = true;
603    new_form->preferred = false;
604    new_form->date_created = base::Time::FromInternalValue(1234);
605    new_form->blacklisted_by_user = false;
606
607    native_forms.push_back(new_form);
608  }
609
610  {
611    PasswordForm new_form;
612    new_form.scheme = PasswordForm::SCHEME_HTML;
613    new_form.signon_realm = "pie";
614    new_form.origin = GURL("http://pie.com");
615    new_form.action = GURL("http://pie.com/submit");
616    new_form.username_element = UTF8ToUTF16("name");
617    new_form.username_value = UTF8ToUTF16("tom");
618    new_form.password_element = UTF8ToUTF16("cork");
619    new_form.password_value = UTF8ToUTF16("password12");
620    new_form.ssl_valid = false;
621    new_form.preferred = true;
622    new_form.date_created = base::Time::FromInternalValue(12345);
623    new_form.blacklisted_by_user = false;
624    sync_forms.push_back(new_form);
625  }
626
627  {
628    PasswordForm new_form;
629    new_form.scheme = PasswordForm::SCHEME_HTML;
630    new_form.signon_realm = "pie";
631    new_form.origin = GURL("http://pie.com");
632    new_form.action = GURL("http://pie.com/submit");
633    new_form.username_element = UTF8ToUTF16("name");
634    new_form.username_value = UTF8ToUTF16("tom");
635    new_form.password_element = UTF8ToUTF16("cork");
636    new_form.password_value = UTF8ToUTF16("password12");
637    new_form.ssl_valid = false;
638    new_form.preferred = true;
639    new_form.date_created = base::Time::FromInternalValue(12345);
640    new_form.blacklisted_by_user = false;
641    expected_forms.push_back(new_form);
642  }
643
644  EXPECT_CALL(*password_store_.get(), FillAutofillableLogins(_))
645      .WillOnce(DoAll(SetArgumentPointee<0>(native_forms), Return(true)));
646  EXPECT_CALL(*password_store_.get(), FillBlacklistLogins(_))
647      .WillOnce(Return(true));
648  EXPECT_CALL(*password_store_.get(), UpdateLoginImpl(_)).Times(1);
649
650  CreateRootHelper create_root(this, syncer::PASSWORDS);
651  StartSyncService(create_root.callback(),
652                   base::Bind(&AddPasswordEntriesCallback, this, sync_forms));
653
654  std::vector<PasswordForm> new_sync_forms;
655  GetPasswordEntriesFromSyncDB(&new_sync_forms);
656
657  EXPECT_EQ(1U, new_sync_forms.size());
658  EXPECT_TRUE(ComparePasswords(expected_forms[0], new_sync_forms[0]));
659}
660