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