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 "base/basictypes.h" 6 #include "base/memory/scoped_temp_dir.h" 7 #include "base/stl_util-inl.h" 8 #include "base/string_util.h" 9 #include "base/synchronization/waitable_event.h" 10 #include "base/time.h" 11 #include "chrome/browser/password_manager/password_form_data.h" 12 #include "chrome/browser/password_manager/password_store_change.h" 13 #include "chrome/browser/password_manager/password_store_x.h" 14 #include "chrome/browser/webdata/web_data_service.h" 15 #include "chrome/common/pref_names.h" 16 #include "chrome/test/signaling_task.h" 17 #include "chrome/test/testing_profile.h" 18 #include "content/common/notification_observer_mock.h" 19 #include "content/common/notification_service.h" 20 #include "testing/gmock/include/gmock/gmock.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 using base::WaitableEvent; 24 using testing::_; 25 using testing::DoAll; 26 using testing::ElementsAreArray; 27 using testing::Pointee; 28 using testing::Property; 29 using testing::WithArg; 30 using webkit_glue::PasswordForm; 31 32 typedef std::vector<PasswordForm*> VectorOfForms; 33 34 namespace { 35 36 class MockPasswordStoreConsumer : public PasswordStoreConsumer { 37 public: 38 MOCK_METHOD2(OnPasswordStoreRequestDone, 39 void(CancelableRequestProvider::Handle, 40 const std::vector<PasswordForm*>&)); 41 }; 42 43 class MockWebDataServiceConsumer : public WebDataServiceConsumer { 44 public: 45 MOCK_METHOD2(OnWebDataServiceRequestDone, void(WebDataService::Handle, 46 const WDTypedResult*)); 47 }; 48 49 // This class will add and remove a mock notification observer from 50 // the DB thread. 51 class DBThreadObserverHelper 52 : public base::RefCountedThreadSafe<DBThreadObserverHelper, 53 BrowserThread::DeleteOnDBThread> { 54 public: 55 DBThreadObserverHelper() : done_event_(true, false) {} 56 57 void Init() { 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 59 BrowserThread::PostTask( 60 BrowserThread::DB, 61 FROM_HERE, 62 NewRunnableMethod(this, &DBThreadObserverHelper::AddObserverTask)); 63 done_event_.Wait(); 64 } 65 66 virtual ~DBThreadObserverHelper() { 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 68 registrar_.RemoveAll(); 69 } 70 71 NotificationObserverMock& observer() { 72 return observer_; 73 } 74 75 protected: 76 friend class base::RefCountedThreadSafe<DBThreadObserverHelper>; 77 78 void AddObserverTask() { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 80 registrar_.Add(&observer_, 81 NotificationType::LOGINS_CHANGED, 82 NotificationService::AllSources()); 83 done_event_.Signal(); 84 } 85 86 WaitableEvent done_event_; 87 NotificationRegistrar registrar_; 88 NotificationObserverMock observer_; 89 }; 90 91 class FailingBackend : public PasswordStoreX::NativeBackend { 92 public: 93 virtual bool Init() { return true; } 94 95 virtual bool AddLogin(const PasswordForm& form) { return false; } 96 virtual bool UpdateLogin(const PasswordForm& form) { return false; } 97 virtual bool RemoveLogin(const PasswordForm& form) { return false; } 98 99 virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin, 100 const base::Time& delete_end) { 101 return false; 102 } 103 104 virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) { 105 return false; 106 } 107 108 virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, 109 const base::Time& get_end, 110 PasswordFormList* forms) { 111 return false; 112 } 113 114 virtual bool GetAutofillableLogins(PasswordFormList* forms) { return false; } 115 virtual bool GetBlacklistLogins(PasswordFormList* forms) { return false; } 116 }; 117 118 class MockBackend : public PasswordStoreX::NativeBackend { 119 public: 120 virtual bool Init() { return true; } 121 122 virtual bool AddLogin(const PasswordForm& form) { 123 all_forms_.push_back(form); 124 return true; 125 } 126 127 virtual bool UpdateLogin(const PasswordForm& form) { 128 for (size_t i = 0; i < all_forms_.size(); ++i) 129 if (CompareForms(all_forms_[i], form, true)) 130 all_forms_[i] = form; 131 return true; 132 } 133 134 virtual bool RemoveLogin(const PasswordForm& form) { 135 for (size_t i = 0; i < all_forms_.size(); ++i) 136 if (CompareForms(all_forms_[i], form, false)) 137 erase(i--); 138 return true; 139 } 140 141 virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin, 142 const base::Time& delete_end) { 143 for (size_t i = 0; i < all_forms_.size(); ++i) { 144 if (delete_begin <= all_forms_[i].date_created && 145 (delete_end.is_null() || all_forms_[i].date_created < delete_end)) 146 erase(i--); 147 } 148 return true; 149 } 150 151 virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) { 152 for (size_t i = 0; i < all_forms_.size(); ++i) 153 if (all_forms_[i].signon_realm == form.signon_realm) 154 forms->push_back(new PasswordForm(all_forms_[i])); 155 return true; 156 } 157 158 virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, 159 const base::Time& get_end, 160 PasswordFormList* forms) { 161 for (size_t i = 0; i < all_forms_.size(); ++i) 162 if (get_begin <= all_forms_[i].date_created && 163 (get_end.is_null() || all_forms_[i].date_created < get_end)) 164 forms->push_back(new PasswordForm(all_forms_[i])); 165 return true; 166 } 167 168 virtual bool GetAutofillableLogins(PasswordFormList* forms) { 169 for (size_t i = 0; i < all_forms_.size(); ++i) 170 if (!all_forms_[i].blacklisted_by_user) 171 forms->push_back(new PasswordForm(all_forms_[i])); 172 return true; 173 } 174 175 virtual bool GetBlacklistLogins(PasswordFormList* forms) { 176 for (size_t i = 0; i < all_forms_.size(); ++i) 177 if (all_forms_[i].blacklisted_by_user) 178 forms->push_back(new PasswordForm(all_forms_[i])); 179 return true; 180 } 181 182 private: 183 void erase(size_t index) { 184 if (index < all_forms_.size() - 1) 185 all_forms_[index] = all_forms_[all_forms_.size() - 1]; 186 all_forms_.pop_back(); 187 } 188 189 bool CompareForms(const PasswordForm& a, const PasswordForm& b, bool update) { 190 // An update check doesn't care about the submit element. 191 if (!update && a.submit_element != b.submit_element) 192 return false; 193 return a.origin == b.origin && 194 a.password_element == b.password_element && 195 a.signon_realm == b.signon_realm && 196 a.username_element == b.username_element && 197 a.username_value == b.username_value; 198 } 199 200 std::vector<PasswordForm> all_forms_; 201 }; 202 203 class MockLoginDatabaseReturn { 204 public: 205 MOCK_METHOD1(OnLoginDatabaseQueryDone, 206 void(const std::vector<PasswordForm*>&)); 207 }; 208 209 class LoginDatabaseQueryTask : public Task { 210 public: 211 LoginDatabaseQueryTask(LoginDatabase* login_db, 212 bool autofillable, 213 MockLoginDatabaseReturn* mock_return) 214 : login_db_(login_db), autofillable_(autofillable), 215 mock_return_(mock_return) { 216 } 217 218 virtual void Run() { 219 std::vector<PasswordForm*> forms; 220 if (autofillable_) 221 login_db_->GetAutofillableLogins(&forms); 222 else 223 login_db_->GetBlacklistLogins(&forms); 224 mock_return_->OnLoginDatabaseQueryDone(forms); 225 } 226 227 private: 228 LoginDatabase* login_db_; 229 bool autofillable_; 230 MockLoginDatabaseReturn* mock_return_; 231 }; 232 233 // Generate |count| expected logins, either autofillable or blacklisted. 234 void InitExpectedForms(bool autofillable, size_t count, VectorOfForms* forms) { 235 const char* domain = autofillable ? "example" : "blacklisted"; 236 for (size_t i = 0; i < count; ++i) { 237 std::string realm = StringPrintf("http://%zu.%s.com", i, domain); 238 std::string origin = StringPrintf("http://%zu.%s.com/origin", i, domain); 239 std::string action = StringPrintf("http://%zu.%s.com/action", i, domain); 240 PasswordFormData data = { 241 PasswordForm::SCHEME_HTML, 242 realm.c_str(), 243 origin.c_str(), 244 action.c_str(), 245 L"submit_element", 246 L"username_element", 247 L"password_element", 248 autofillable ? L"username_value" : NULL, 249 autofillable ? L"password_value" : NULL, 250 autofillable, false, i + 1 }; 251 forms->push_back(CreatePasswordFormFromData(data)); 252 } 253 } 254 255 } // anonymous namespace 256 257 // LoginDatabase isn't reference counted, but in these unit tests that won't be 258 // a problem as it always outlives the threads we post tasks to. 259 template<> 260 struct RunnableMethodTraits<LoginDatabase> { 261 void RetainCallee(LoginDatabase*) {} 262 void ReleaseCallee(LoginDatabase*) {} 263 }; 264 265 enum BackendType { 266 NO_BACKEND, 267 FAILING_BACKEND, 268 WORKING_BACKEND 269 }; 270 271 class PasswordStoreXTest : public testing::TestWithParam<BackendType> { 272 protected: 273 PasswordStoreXTest() 274 : ui_thread_(BrowserThread::UI, &message_loop_), 275 db_thread_(BrowserThread::DB) { 276 } 277 278 virtual void SetUp() { 279 ASSERT_TRUE(db_thread_.Start()); 280 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 281 282 profile_.reset(new TestingProfile()); 283 284 login_db_.reset(new LoginDatabase()); 285 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append("login_test"))); 286 287 wds_ = new WebDataService(); 288 ASSERT_TRUE(wds_->Init(temp_dir_.path())); 289 } 290 291 virtual void TearDown() { 292 wds_->Shutdown(); 293 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); 294 MessageLoop::current()->Run(); 295 db_thread_.Stop(); 296 } 297 298 PasswordStoreX::NativeBackend* GetBackend() { 299 switch (GetParam()) { 300 case FAILING_BACKEND: 301 return new FailingBackend(); 302 case WORKING_BACKEND: 303 return new MockBackend(); 304 default: 305 return NULL; 306 } 307 } 308 309 MessageLoopForUI message_loop_; 310 BrowserThread ui_thread_; 311 BrowserThread db_thread_; // PasswordStore, WDS schedule work on this thread. 312 313 scoped_ptr<LoginDatabase> login_db_; 314 scoped_ptr<TestingProfile> profile_; 315 scoped_refptr<WebDataService> wds_; 316 ScopedTempDir temp_dir_; 317 }; 318 319 ACTION(STLDeleteElements0) { 320 STLDeleteContainerPointers(arg0.begin(), arg0.end()); 321 } 322 323 ACTION(QuitUIMessageLoop) { 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 325 MessageLoop::current()->Quit(); 326 } 327 328 MATCHER(EmptyWDResult, "") { 329 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( 330 arg)->GetValue().empty(); 331 } 332 333 TEST_P(PasswordStoreXTest, WDSMigration) { 334 VectorOfForms expected_autofillable; 335 InitExpectedForms(true, 5, &expected_autofillable); 336 337 VectorOfForms expected_blacklisted; 338 InitExpectedForms(false, 5, &expected_blacklisted); 339 340 // Populate the WDS with logins that should be migrated. 341 for (VectorOfForms::iterator it = expected_autofillable.begin(); 342 it != expected_autofillable.end(); ++it) { 343 wds_->AddLogin(**it); 344 } 345 for (VectorOfForms::iterator it = expected_blacklisted.begin(); 346 it != expected_blacklisted.end(); ++it) { 347 wds_->AddLogin(**it); 348 } 349 350 // The WDS schedules tasks to run on the DB thread so we schedule yet another 351 // task to notify us that it's safe to carry on with the test. 352 WaitableEvent done(false, false); 353 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 354 new SignalingTask(&done)); 355 done.Wait(); 356 357 // Initializing the PasswordStore should trigger a migration. 358 scoped_refptr<PasswordStoreX> store( 359 new PasswordStoreX(login_db_.release(), 360 profile_.get(), 361 wds_.get(), 362 GetBackend())); 363 store->Init(); 364 365 // Check that the migration preference has not been initialized. 366 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( 367 prefs::kLoginDatabaseMigrated)); 368 369 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task 370 // to signal us when it is safe to continue. 371 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 372 new SignalingTask(&done)); 373 done.Wait(); 374 375 // Let the WDS callbacks proceed so the logins can be migrated. 376 MessageLoop::current()->RunAllPending(); 377 378 MockPasswordStoreConsumer consumer; 379 380 // Make sure we quit the MessageLoop even if the test fails. 381 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) 382 .WillByDefault(QuitUIMessageLoop()); 383 384 // The autofillable forms should have been migrated from the WDS to the login 385 // database. 386 EXPECT_CALL(consumer, 387 OnPasswordStoreRequestDone(_, 388 ContainsAllPasswordForms(expected_autofillable))) 389 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); 390 391 store->GetAutofillableLogins(&consumer); 392 MessageLoop::current()->Run(); 393 394 // The blacklisted forms should have been migrated from the WDS to the login 395 // database. 396 EXPECT_CALL(consumer, 397 OnPasswordStoreRequestDone(_, 398 ContainsAllPasswordForms(expected_blacklisted))) 399 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); 400 401 store->GetBlacklistLogins(&consumer); 402 MessageLoop::current()->Run(); 403 404 // Check that the migration updated the migrated preference. 405 ASSERT_TRUE(profile_->GetPrefs()->GetBoolean(prefs::kLoginDatabaseMigrated)); 406 407 MockWebDataServiceConsumer wds_consumer; 408 409 // No autofillable logins should be left in the WDS. 410 EXPECT_CALL(wds_consumer, 411 OnWebDataServiceRequestDone(_, EmptyWDResult())); 412 413 wds_->GetAutofillableLogins(&wds_consumer); 414 415 // Wait for the WDS methods to execute on the DB thread. 416 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 417 new SignalingTask(&done)); 418 done.Wait(); 419 420 // Handle the callback from the WDS. 421 MessageLoop::current()->RunAllPending(); 422 423 // Likewise, no blacklisted logins should be left in the WDS. 424 EXPECT_CALL(wds_consumer, 425 OnWebDataServiceRequestDone(_, EmptyWDResult())); 426 427 wds_->GetBlacklistLogins(&wds_consumer); 428 429 // Wait for the WDS methods to execute on the DB thread. 430 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 431 new SignalingTask(&done)); 432 done.Wait(); 433 434 // Handle the callback from the WDS. 435 MessageLoop::current()->RunAllPending(); 436 437 STLDeleteElements(&expected_autofillable); 438 STLDeleteElements(&expected_blacklisted); 439 440 store->Shutdown(); 441 } 442 443 TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) { 444 PasswordFormData wds_data[] = { 445 { PasswordForm::SCHEME_HTML, 446 "http://bar.example.com", 447 "http://bar.example.com/origin", 448 "http://bar.example.com/action", 449 L"submit_element", 450 L"username_element", 451 L"password_element", 452 L"username_value", 453 L"password_value", 454 true, false, 1 }, 455 }; 456 457 VectorOfForms unexpected_autofillable; 458 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(wds_data); ++i) { 459 unexpected_autofillable.push_back( 460 CreatePasswordFormFromData(wds_data[i])); 461 } 462 463 // Populate the WDS with logins that should be migrated. 464 for (VectorOfForms::iterator it = unexpected_autofillable.begin(); 465 it != unexpected_autofillable.end(); ++it) { 466 wds_->AddLogin(**it); 467 } 468 469 // The WDS schedules tasks to run on the DB thread so we schedule yet another 470 // task to notify us that it's safe to carry on with the test. 471 WaitableEvent done(false, false); 472 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 473 new SignalingTask(&done)); 474 done.Wait(); 475 476 // Prentend that the migration has already taken place. 477 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, 478 true); 479 480 // Initializing the PasswordStore shouldn't trigger a migration. 481 scoped_refptr<PasswordStoreX> store( 482 new PasswordStoreX(login_db_.release(), 483 profile_.get(), 484 wds_.get(), 485 GetBackend())); 486 store->Init(); 487 488 MockPasswordStoreConsumer consumer; 489 // Make sure we quit the MessageLoop even if the test fails. 490 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) 491 .WillByDefault(QuitUIMessageLoop()); 492 493 // No forms should be migrated. 494 VectorOfForms empty; 495 EXPECT_CALL(consumer, 496 OnPasswordStoreRequestDone(_, 497 ContainsAllPasswordForms(empty))) 498 .WillOnce(QuitUIMessageLoop()); 499 500 store->GetAutofillableLogins(&consumer); 501 MessageLoop::current()->Run(); 502 503 STLDeleteElements(&unexpected_autofillable); 504 505 store->Shutdown(); 506 } 507 508 TEST_P(PasswordStoreXTest, Notifications) { 509 // Pretend that the migration has already taken place. 510 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, 511 true); 512 513 // Initializing the PasswordStore shouldn't trigger a migration. 514 scoped_refptr<PasswordStoreX> store( 515 new PasswordStoreX(login_db_.release(), 516 profile_.get(), 517 wds_.get(), 518 GetBackend())); 519 store->Init(); 520 521 PasswordFormData form_data = 522 { PasswordForm::SCHEME_HTML, 523 "http://bar.example.com", 524 "http://bar.example.com/origin", 525 "http://bar.example.com/action", 526 L"submit_element", 527 L"username_element", 528 L"password_element", 529 L"username_value", 530 L"password_value", 531 true, false, 1 }; 532 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data)); 533 534 scoped_refptr<DBThreadObserverHelper> helper = new DBThreadObserverHelper; 535 helper->Init(); 536 537 const PasswordStoreChange expected_add_changes[] = { 538 PasswordStoreChange(PasswordStoreChange::ADD, *form), 539 }; 540 541 EXPECT_CALL(helper->observer(), 542 Observe(NotificationType(NotificationType::LOGINS_CHANGED), 543 NotificationService::AllSources(), 544 Property(&Details<const PasswordStoreChangeList>::ptr, 545 Pointee(ElementsAreArray( 546 expected_add_changes))))); 547 548 // Adding a login should trigger a notification. 549 store->AddLogin(*form); 550 551 // The PasswordStore schedules tasks to run on the DB thread so we schedule 552 // yet another task to notify us that it's safe to carry on with the test. 553 WaitableEvent done(false, false); 554 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 555 new SignalingTask(&done)); 556 done.Wait(); 557 558 // Change the password. 559 form->password_value = WideToUTF16(L"a different password"); 560 561 const PasswordStoreChange expected_update_changes[] = { 562 PasswordStoreChange(PasswordStoreChange::UPDATE, *form), 563 }; 564 565 EXPECT_CALL(helper->observer(), 566 Observe(NotificationType(NotificationType::LOGINS_CHANGED), 567 NotificationService::AllSources(), 568 Property(&Details<const PasswordStoreChangeList>::ptr, 569 Pointee(ElementsAreArray( 570 expected_update_changes))))); 571 572 // Updating the login with the new password should trigger a notification. 573 store->UpdateLogin(*form); 574 575 // Wait for PasswordStore to send the notification. 576 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 577 new SignalingTask(&done)); 578 done.Wait(); 579 580 const PasswordStoreChange expected_delete_changes[] = { 581 PasswordStoreChange(PasswordStoreChange::REMOVE, *form), 582 }; 583 584 EXPECT_CALL(helper->observer(), 585 Observe(NotificationType(NotificationType::LOGINS_CHANGED), 586 NotificationService::AllSources(), 587 Property(&Details<const PasswordStoreChangeList>::ptr, 588 Pointee(ElementsAreArray( 589 expected_delete_changes))))); 590 591 // Deleting the login should trigger a notification. 592 store->RemoveLogin(*form); 593 594 // Wait for PasswordStore to send the notification. 595 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 596 new SignalingTask(&done)); 597 done.Wait(); 598 599 store->Shutdown(); 600 } 601 602 TEST_P(PasswordStoreXTest, NativeMigration) { 603 VectorOfForms expected_autofillable; 604 InitExpectedForms(true, 50, &expected_autofillable); 605 606 VectorOfForms expected_blacklisted; 607 InitExpectedForms(false, 50, &expected_blacklisted); 608 609 // Get the initial size of the login DB file, before we populate it. 610 // This will be used later to make sure it gets back to this size. 611 const FilePath login_db_file = temp_dir_.path().Append("login_test"); 612 base::PlatformFileInfo db_file_start_info; 613 ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_start_info)); 614 615 LoginDatabase* login_db = login_db_.get(); 616 617 // Populate the login DB with logins that should be migrated. 618 for (VectorOfForms::iterator it = expected_autofillable.begin(); 619 it != expected_autofillable.end(); ++it) { 620 BrowserThread::PostTask(BrowserThread::DB, 621 FROM_HERE, 622 NewRunnableMethod(login_db, 623 &LoginDatabase::AddLogin, 624 **it)); 625 } 626 for (VectorOfForms::iterator it = expected_blacklisted.begin(); 627 it != expected_blacklisted.end(); ++it) { 628 BrowserThread::PostTask(BrowserThread::DB, 629 FROM_HERE, 630 NewRunnableMethod(login_db, 631 &LoginDatabase::AddLogin, 632 **it)); 633 } 634 635 // Schedule another task on the DB thread to notify us that it's safe to 636 // carry on with the test. 637 WaitableEvent done(false, false); 638 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 639 new SignalingTask(&done)); 640 done.Wait(); 641 642 // Get the new size of the login DB file. We expect it to be larger. 643 base::PlatformFileInfo db_file_full_info; 644 ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_full_info)); 645 EXPECT_GT(db_file_full_info.size, db_file_start_info.size); 646 647 // Pretend that the WDS migration has already taken place. 648 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, 649 true); 650 651 // Initializing the PasswordStore shouldn't trigger a native migration (yet). 652 scoped_refptr<PasswordStoreX> store( 653 new PasswordStoreX(login_db_.release(), 654 profile_.get(), 655 wds_.get(), 656 GetBackend())); 657 store->Init(); 658 659 MockPasswordStoreConsumer consumer; 660 661 // Make sure we quit the MessageLoop even if the test fails. 662 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) 663 .WillByDefault(QuitUIMessageLoop()); 664 665 // The autofillable forms should have been migrated to the native backend. 666 EXPECT_CALL(consumer, 667 OnPasswordStoreRequestDone(_, 668 ContainsAllPasswordForms(expected_autofillable))) 669 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); 670 671 store->GetAutofillableLogins(&consumer); 672 MessageLoop::current()->Run(); 673 674 // The blacklisted forms should have been migrated to the native backend. 675 EXPECT_CALL(consumer, 676 OnPasswordStoreRequestDone(_, 677 ContainsAllPasswordForms(expected_blacklisted))) 678 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); 679 680 store->GetBlacklistLogins(&consumer); 681 MessageLoop::current()->Run(); 682 683 VectorOfForms empty; 684 MockLoginDatabaseReturn ld_return; 685 686 if (GetParam() == WORKING_BACKEND) { 687 // No autofillable logins should be left in the login DB. 688 EXPECT_CALL(ld_return, 689 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty))); 690 } else { 691 // The autofillable logins should still be in the login DB. 692 EXPECT_CALL(ld_return, 693 OnLoginDatabaseQueryDone( 694 ContainsAllPasswordForms(expected_autofillable))) 695 .WillOnce(WithArg<0>(STLDeleteElements0())); 696 } 697 698 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 699 new LoginDatabaseQueryTask(login_db, true, &ld_return)); 700 701 // Wait for the login DB methods to execute on the DB thread. 702 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 703 new SignalingTask(&done)); 704 done.Wait(); 705 706 if (GetParam() == WORKING_BACKEND) { 707 // Likewise, no blacklisted logins should be left in the login DB. 708 EXPECT_CALL(ld_return, 709 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty))); 710 } else { 711 // The blacklisted logins should still be in the login DB. 712 EXPECT_CALL(ld_return, 713 OnLoginDatabaseQueryDone( 714 ContainsAllPasswordForms(expected_blacklisted))) 715 .WillOnce(WithArg<0>(STLDeleteElements0())); 716 } 717 718 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 719 new LoginDatabaseQueryTask(login_db, false, &ld_return)); 720 721 // Wait for the login DB methods to execute on the DB thread. 722 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 723 new SignalingTask(&done)); 724 done.Wait(); 725 726 if (GetParam() == WORKING_BACKEND) { 727 // If the migration succeeded, then not only should there be no logins left 728 // in the login DB, but also the file should have been deleted and then 729 // recreated. We approximate checking for this by checking that the file 730 // size is equal to the size before we populated it, even though it was 731 // larger after populating it. 732 base::PlatformFileInfo db_file_end_info; 733 ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_end_info)); 734 EXPECT_EQ(db_file_start_info.size, db_file_end_info.size); 735 } 736 737 STLDeleteElements(&expected_autofillable); 738 STLDeleteElements(&expected_blacklisted); 739 740 store->Shutdown(); 741 } 742 743 INSTANTIATE_TEST_CASE_P(NoBackend, 744 PasswordStoreXTest, 745 testing::Values(NO_BACKEND)); 746 INSTANTIATE_TEST_CASE_P(FailingBackend, 747 PasswordStoreXTest, 748 testing::Values(FAILING_BACKEND)); 749 INSTANTIATE_TEST_CASE_P(WorkingBackend, 750 PasswordStoreXTest, 751 testing::Values(WORKING_BACKEND)); 752