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 |