| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/basictypes.h" | 5 #include "base/basictypes.h" |
| 6 #include "base/scoped_temp_dir.h" | 6 #include "base/scoped_temp_dir.h" |
| 7 #include "base/stl_util-inl.h" | 7 #include "base/stl_util-inl.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "base/waitable_event.h" | 10 #include "base/waitable_event.h" |
| 11 #include "chrome/browser/password_manager/password_form_data.h" | 11 #include "chrome/browser/password_manager/password_form_data.h" |
| 12 #include "chrome/browser/password_manager/password_store_change.h" | 12 #include "chrome/browser/password_manager/password_store_change.h" |
| 13 #include "chrome/browser/password_manager/password_store_x.h" | 13 #include "chrome/browser/password_manager/password_store_x.h" |
| 14 #include "chrome/browser/webdata/web_data_service.h" | 14 #include "chrome/browser/webdata/web_data_service.h" |
| 15 #include "chrome/common/notification_service.h" | 15 #include "chrome/common/notification_service.h" |
| 16 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
| 17 #include "chrome/test/testing_profile.h" | 17 #include "chrome/test/testing_profile.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 using base::WaitableEvent; | 21 using base::WaitableEvent; |
| 22 using testing::_; | 22 using testing::_; |
| 23 using testing::DoAll; | 23 using testing::DoAll; |
| 24 using testing::ElementsAreArray; | 24 using testing::ElementsAreArray; |
| 25 using testing::Pointee; | 25 using testing::Pointee; |
| 26 using testing::Property; | 26 using testing::Property; |
| 27 using testing::WithArg; | 27 using testing::WithArg; |
| 28 using webkit_glue::PasswordForm; | 28 using webkit_glue::PasswordForm; |
| 29 | 29 |
| 30 typedef std::vector<PasswordForm*> VectorOfForms; |
| 31 |
| 30 namespace { | 32 namespace { |
| 31 | 33 |
| 32 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 34 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
| 33 public: | 35 public: |
| 34 MOCK_METHOD2(OnPasswordStoreRequestDone, | 36 MOCK_METHOD2(OnPasswordStoreRequestDone, |
| 35 void(int, const std::vector<PasswordForm*>&)); | 37 void(int, const std::vector<PasswordForm*>&)); |
| 36 }; | 38 }; |
| 37 | 39 |
| 38 class MockWebDataServiceConsumer : public WebDataServiceConsumer { | 40 class MockWebDataServiceConsumer : public WebDataServiceConsumer { |
| 39 public: | 41 public: |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 login_db_->GetBlacklistLogins(&forms); | 238 login_db_->GetBlacklistLogins(&forms); |
| 237 mock_return_->OnLoginDatabaseQueryDone(forms); | 239 mock_return_->OnLoginDatabaseQueryDone(forms); |
| 238 } | 240 } |
| 239 | 241 |
| 240 private: | 242 private: |
| 241 LoginDatabase* login_db_; | 243 LoginDatabase* login_db_; |
| 242 bool autofillable_; | 244 bool autofillable_; |
| 243 MockLoginDatabaseReturn* mock_return_; | 245 MockLoginDatabaseReturn* mock_return_; |
| 244 }; | 246 }; |
| 245 | 247 |
| 246 const PasswordFormData g_autofillable_data[] = { | 248 // Generate |count| expected logins, either autofillable or blacklisted. |
| 247 { PasswordForm::SCHEME_HTML, | 249 void InitExpectedForms(bool autofillable, size_t count, VectorOfForms* forms) { |
| 248 "http://foo.example.com", | 250 const char* domain = autofillable ? "example" : "blacklisted"; |
| 249 "http://foo.example.com/origin", | 251 for (size_t i = 0; i < count; ++i) { |
| 250 "http://foo.example.com/action", | 252 std::string realm = StringPrintf("http://%zu.%s.com", i, domain); |
| 251 L"submit_element", | 253 std::string origin = StringPrintf("http://%zu.%s.com/origin", i, domain); |
| 252 L"username_element", | 254 std::string action = StringPrintf("http://%zu.%s.com/action", i, domain); |
| 253 L"password_element", | 255 PasswordFormData data = { |
| 254 L"username_value", | 256 PasswordForm::SCHEME_HTML, |
| 255 L"password_value", | 257 realm.c_str(), |
| 256 true, false, 1 }, | 258 origin.c_str(), |
| 257 { PasswordForm::SCHEME_HTML, | 259 action.c_str(), |
| 258 "http://bar.example.com", | 260 L"submit_element", |
| 259 "http://bar.example.com/origin", | 261 L"username_element", |
| 260 "http://bar.example.com/action", | 262 L"password_element", |
| 261 L"submit_element", | 263 autofillable ? L"username_value" : NULL, |
| 262 L"username_element", | 264 autofillable ? L"password_value" : NULL, |
| 263 L"password_element", | 265 autofillable, false, i + 1 }; |
| 264 L"username_value", | 266 forms->push_back(CreatePasswordFormFromData(data)); |
| 265 L"password_value", | 267 } |
| 266 true, false, 2 }, | 268 } |
| 267 { PasswordForm::SCHEME_HTML, | |
| 268 "http://baz.example.com", | |
| 269 "http://baz.example.com/origin", | |
| 270 "http://baz.example.com/action", | |
| 271 L"submit_element", | |
| 272 L"username_element", | |
| 273 L"password_element", | |
| 274 L"username_value", | |
| 275 L"password_value", | |
| 276 true, false, 3 }, | |
| 277 }; | |
| 278 const PasswordFormData g_blacklisted_data[] = { | |
| 279 { PasswordForm::SCHEME_HTML, | |
| 280 "http://blacklisted.example.com", | |
| 281 "http://blacklisted.example.com/origin", | |
| 282 "http://blacklisted.example.com/action", | |
| 283 L"submit_element", | |
| 284 L"username_element", | |
| 285 L"password_element", | |
| 286 NULL, | |
| 287 NULL, | |
| 288 false, false, 1 }, | |
| 289 { PasswordForm::SCHEME_HTML, | |
| 290 "http://blacklisted2.example.com", | |
| 291 "http://blacklisted2.example.com/origin", | |
| 292 "http://blacklisted2.example.com/action", | |
| 293 L"submit_element", | |
| 294 L"username_element", | |
| 295 L"password_element", | |
| 296 NULL, | |
| 297 NULL, | |
| 298 false, false, 2 }, | |
| 299 }; | |
| 300 | 269 |
| 301 } // anonymous namespace | 270 } // anonymous namespace |
| 302 | 271 |
| 303 typedef std::vector<PasswordForm*> VectorOfForms; | |
| 304 | |
| 305 // LoginDatabase isn't reference counted, but in these unit tests that won't be | 272 // LoginDatabase isn't reference counted, but in these unit tests that won't be |
| 306 // a problem as it always outlives the threads we post tasks to. | 273 // a problem as it always outlives the threads we post tasks to. |
| 307 template<> | 274 template<> |
| 308 struct RunnableMethodTraits<LoginDatabase> { | 275 struct RunnableMethodTraits<LoginDatabase> { |
| 309 void RetainCallee(LoginDatabase*) {} | 276 void RetainCallee(LoginDatabase*) {} |
| 310 void ReleaseCallee(LoginDatabase*) {} | 277 void ReleaseCallee(LoginDatabase*) {} |
| 311 }; | 278 }; |
| 312 | 279 |
| 313 enum BackendType { | 280 enum BackendType { |
| 314 NO_BACKEND, | 281 NO_BACKEND, |
| 315 FAILING_BACKEND, | 282 FAILING_BACKEND, |
| 316 WORKING_BACKEND | 283 WORKING_BACKEND |
| 317 }; | 284 }; |
| 318 | 285 |
| 319 class PasswordStoreXTest : public testing::TestWithParam<BackendType> { | 286 class PasswordStoreXTest : public testing::TestWithParam<BackendType> { |
| 320 protected: | 287 protected: |
| 321 PasswordStoreXTest() | 288 PasswordStoreXTest() |
| 322 : ui_thread_(ChromeThread::UI, &message_loop_), | 289 : ui_thread_(ChromeThread::UI, &message_loop_), |
| 323 db_thread_(ChromeThread::DB) { | 290 db_thread_(ChromeThread::DB) { |
| 324 } | 291 } |
| 325 | 292 |
| 326 virtual void SetUp() { | 293 virtual void SetUp() { |
| 327 ASSERT_TRUE(db_thread_.Start()); | 294 ASSERT_TRUE(db_thread_.Start()); |
| 328 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 295 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 329 | 296 |
| 330 profile_.reset(new TestingProfile()); | 297 profile_.reset(new TestingProfile()); |
| 331 | 298 |
| 332 login_db_.reset(new LoginDatabase()); | 299 login_db_.reset(new LoginDatabase()); |
| 333 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append( | 300 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append("login_test"))); |
| 334 FILE_PATH_LITERAL("login_test")))); | |
| 335 | 301 |
| 336 wds_ = new WebDataService(); | 302 wds_ = new WebDataService(); |
| 337 ASSERT_TRUE(wds_->Init(temp_dir_.path())); | 303 ASSERT_TRUE(wds_->Init(temp_dir_.path())); |
| 338 } | 304 } |
| 339 | 305 |
| 340 virtual void TearDown() { | 306 virtual void TearDown() { |
| 341 wds_->Shutdown(); | 307 wds_->Shutdown(); |
| 342 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); | 308 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); |
| 343 MessageLoop::current()->Run(); | 309 MessageLoop::current()->Run(); |
| 344 db_thread_.Stop(); | 310 db_thread_.Stop(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 374 MessageLoop::current()->Quit(); | 340 MessageLoop::current()->Quit(); |
| 375 } | 341 } |
| 376 | 342 |
| 377 MATCHER(EmptyWDResult, "") { | 343 MATCHER(EmptyWDResult, "") { |
| 378 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( | 344 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( |
| 379 arg)->GetValue().empty(); | 345 arg)->GetValue().empty(); |
| 380 } | 346 } |
| 381 | 347 |
| 382 TEST_P(PasswordStoreXTest, WDSMigration) { | 348 TEST_P(PasswordStoreXTest, WDSMigration) { |
| 383 VectorOfForms expected_autofillable; | 349 VectorOfForms expected_autofillable; |
| 384 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) { | 350 InitExpectedForms(true, 5, &expected_autofillable); |
| 385 expected_autofillable.push_back( | |
| 386 CreatePasswordFormFromData(g_autofillable_data[i])); | |
| 387 } | |
| 388 | 351 |
| 389 VectorOfForms expected_blacklisted; | 352 VectorOfForms expected_blacklisted; |
| 390 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) { | 353 InitExpectedForms(false, 5, &expected_blacklisted); |
| 391 expected_blacklisted.push_back( | |
| 392 CreatePasswordFormFromData(g_blacklisted_data[i])); | |
| 393 } | |
| 394 | 354 |
| 395 // Populate the WDS with logins that should be migrated. | 355 // Populate the WDS with logins that should be migrated. |
| 396 for (VectorOfForms::iterator it = expected_autofillable.begin(); | 356 for (VectorOfForms::iterator it = expected_autofillable.begin(); |
| 397 it != expected_autofillable.end(); ++it) { | 357 it != expected_autofillable.end(); ++it) { |
| 398 wds_->AddLogin(**it); | 358 wds_->AddLogin(**it); |
| 399 } | 359 } |
| 400 for (VectorOfForms::iterator it = expected_blacklisted.begin(); | 360 for (VectorOfForms::iterator it = expected_blacklisted.begin(); |
| 401 it != expected_blacklisted.end(); ++it) { | 361 it != expected_blacklisted.end(); ++it) { |
| 402 wds_->AddLogin(**it); | 362 wds_->AddLogin(**it); |
| 403 } | 363 } |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 // Deleting the login should trigger a notification. | 595 // Deleting the login should trigger a notification. |
| 636 store->RemoveLogin(*form); | 596 store->RemoveLogin(*form); |
| 637 | 597 |
| 638 // Wait for PasswordStore to send the notification. | 598 // Wait for PasswordStore to send the notification. |
| 639 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 599 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 640 done.Wait(); | 600 done.Wait(); |
| 641 } | 601 } |
| 642 | 602 |
| 643 TEST_P(PasswordStoreXTest, NativeMigration) { | 603 TEST_P(PasswordStoreXTest, NativeMigration) { |
| 644 VectorOfForms expected_autofillable; | 604 VectorOfForms expected_autofillable; |
| 645 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) { | 605 InitExpectedForms(true, 50, &expected_autofillable); |
| 646 expected_autofillable.push_back( | |
| 647 CreatePasswordFormFromData(g_autofillable_data[i])); | |
| 648 } | |
| 649 | 606 |
| 650 VectorOfForms expected_blacklisted; | 607 VectorOfForms expected_blacklisted; |
| 651 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) { | 608 InitExpectedForms(false, 50, &expected_blacklisted); |
| 652 expected_blacklisted.push_back( | 609 |
| 653 CreatePasswordFormFromData(g_blacklisted_data[i])); | 610 // Get the initial size of the login DB file, before we populate it. |
| 654 } | 611 // This will be used later to make sure it gets back to this size. |
| 612 const FilePath login_db_file = temp_dir_.path().Append("login_test"); |
| 613 file_util::FileInfo db_file_start_info; |
| 614 ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_start_info)); |
| 655 | 615 |
| 656 LoginDatabase* login_db = login_db_.get(); | 616 LoginDatabase* login_db = login_db_.get(); |
| 657 | 617 |
| 658 // Populate the login DB with logins that should be migrated. | 618 // Populate the login DB with logins that should be migrated. |
| 659 for (VectorOfForms::iterator it = expected_autofillable.begin(); | 619 for (VectorOfForms::iterator it = expected_autofillable.begin(); |
| 660 it != expected_autofillable.end(); ++it) { | 620 it != expected_autofillable.end(); ++it) { |
| 661 ChromeThread::PostTask(ChromeThread::DB, | 621 ChromeThread::PostTask(ChromeThread::DB, |
| 662 FROM_HERE, | 622 FROM_HERE, |
| 663 NewRunnableMethod(login_db, | 623 NewRunnableMethod(login_db, |
| 664 &LoginDatabase::AddLogin, | 624 &LoginDatabase::AddLogin, |
| 665 **it)); | 625 **it)); |
| 666 } | 626 } |
| 667 for (VectorOfForms::iterator it = expected_blacklisted.begin(); | 627 for (VectorOfForms::iterator it = expected_blacklisted.begin(); |
| 668 it != expected_blacklisted.end(); ++it) { | 628 it != expected_blacklisted.end(); ++it) { |
| 669 ChromeThread::PostTask(ChromeThread::DB, | 629 ChromeThread::PostTask(ChromeThread::DB, |
| 670 FROM_HERE, | 630 FROM_HERE, |
| 671 NewRunnableMethod(login_db, | 631 NewRunnableMethod(login_db, |
| 672 &LoginDatabase::AddLogin, | 632 &LoginDatabase::AddLogin, |
| 673 **it)); | 633 **it)); |
| 674 } | 634 } |
| 675 | 635 |
| 676 // Schedule another task on the DB thread to notify us that it's safe to | 636 // Schedule another task on the DB thread to notify us that it's safe to |
| 677 // carry on with the test. | 637 // carry on with the test. |
| 678 WaitableEvent done(false, false); | 638 WaitableEvent done(false, false); |
| 679 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 639 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 680 done.Wait(); | 640 done.Wait(); |
| 681 | 641 |
| 642 // Get the new size of the login DB file. We expect it to be larger. |
| 643 file_util::FileInfo 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 |
| 682 // Pretend that the WDS migration has already taken place. | 647 // Pretend that the WDS migration has already taken place. |
| 683 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, | 648 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, |
| 684 true); | 649 true); |
| 685 | 650 |
| 686 // Initializing the PasswordStore shouldn't trigger a native migration (yet). | 651 // Initializing the PasswordStore shouldn't trigger a native migration (yet). |
| 687 scoped_refptr<PasswordStoreX> store( | 652 scoped_refptr<PasswordStoreX> store( |
| 688 new PasswordStoreX(login_db_.release(), | 653 new PasswordStoreX(login_db_.release(), |
| 689 profile_.get(), | 654 profile_.get(), |
| 690 wds_.get(), | 655 wds_.get(), |
| 691 GetBackend())); | 656 GetBackend())); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 .WillOnce(WithArg<0>(STLDeleteElements0())); | 714 .WillOnce(WithArg<0>(STLDeleteElements0())); |
| 750 } | 715 } |
| 751 | 716 |
| 752 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, | 717 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, |
| 753 new LoginDatabaseQueryTask(login_db, false, &ld_return)); | 718 new LoginDatabaseQueryTask(login_db, false, &ld_return)); |
| 754 | 719 |
| 755 // Wait for the login DB methods to execute on the DB thread. | 720 // Wait for the login DB methods to execute on the DB thread. |
| 756 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 721 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 757 done.Wait(); | 722 done.Wait(); |
| 758 | 723 |
| 724 if (GetParam() == WORKING_BACKEND) { |
| 725 // If the migration succeeded, then not only should there be no logins left |
| 726 // in the login DB, but also the file should have been deleted and then |
| 727 // recreated. We approximate checking for this by checking that the file |
| 728 // size is equal to the size before we populated it, even though it was |
| 729 // larger after populating it. |
| 730 file_util::FileInfo db_file_end_info; |
| 731 ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_end_info)); |
| 732 EXPECT_EQ(db_file_start_info.size, db_file_end_info.size); |
| 733 } |
| 734 |
| 759 STLDeleteElements(&expected_autofillable); | 735 STLDeleteElements(&expected_autofillable); |
| 760 STLDeleteElements(&expected_blacklisted); | 736 STLDeleteElements(&expected_blacklisted); |
| 761 } | 737 } |
| 762 | 738 |
| 763 INSTANTIATE_TEST_CASE_P(NoBackend, | 739 INSTANTIATE_TEST_CASE_P(NoBackend, |
| 764 PasswordStoreXTest, | 740 PasswordStoreXTest, |
| 765 testing::Values(NO_BACKEND)); | 741 testing::Values(NO_BACKEND)); |
| 766 INSTANTIATE_TEST_CASE_P(FailingBackend, | 742 INSTANTIATE_TEST_CASE_P(FailingBackend, |
| 767 PasswordStoreXTest, | 743 PasswordStoreXTest, |
| 768 testing::Values(FAILING_BACKEND)); | 744 testing::Values(FAILING_BACKEND)); |
| 769 INSTANTIATE_TEST_CASE_P(WorkingBackend, | 745 INSTANTIATE_TEST_CASE_P(WorkingBackend, |
| 770 PasswordStoreXTest, | 746 PasswordStoreXTest, |
| 771 testing::Values(WORKING_BACKEND)); | 747 testing::Values(WORKING_BACKEND)); |
| OLD | NEW |