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