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 <windows.h> | 5 #include <windows.h> |
6 #include <wincrypt.h> | 6 #include <wincrypt.h> |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/scoped_ptr.h" | 11 #include "base/scoped_ptr.h" |
12 #include "base/scoped_temp_dir.h" | 12 #include "base/scoped_temp_dir.h" |
13 #include "base/time.h" | 13 #include "base/time.h" |
14 #include "base/waitable_event.h" | 14 #include "base/waitable_event.h" |
15 #include "chrome/browser/chrome_thread.h" | 15 #include "chrome/browser/chrome_thread.h" |
16 #include "chrome/browser/password_manager/password_form_data.h" | 16 #include "chrome/browser/password_manager/password_form_data.h" |
17 #include "chrome/browser/password_manager/password_store_win.h" | 17 #include "chrome/browser/password_manager/password_store_win.h" |
18 #include "chrome/browser/password_manager/ie7_password.h" | 18 #include "chrome/browser/password_manager/ie7_password.h" |
19 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
20 #include "chrome/test/testing_profile.h" | 20 #include "chrome/test/testing_profile.h" |
21 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
23 | 23 |
24 using base::WaitableEvent; | 24 using base::WaitableEvent; |
25 using testing::_; | 25 using testing::_; |
| 26 using testing::DoAll; |
| 27 using testing::WithArg; |
26 using webkit_glue::PasswordForm; | 28 using webkit_glue::PasswordForm; |
27 | 29 |
28 namespace { | 30 namespace { |
29 | 31 |
30 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 32 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
31 public: | 33 public: |
32 MOCK_METHOD2(OnPasswordStoreRequestDone, | 34 MOCK_METHOD2(OnPasswordStoreRequestDone, |
33 void(int, const std::vector<webkit_glue::PasswordForm*>&)); | 35 void(int, const std::vector<webkit_glue::PasswordForm*>&)); |
34 }; | 36 }; |
35 | 37 |
36 class MockWebDataServiceConsumer : public WebDataServiceConsumer { | 38 class MockWebDataServiceConsumer : public WebDataServiceConsumer { |
37 public: | 39 public: |
38 MOCK_METHOD2(OnWebDataServiceRequestDone, | 40 MOCK_METHOD2(OnWebDataServiceRequestDone, |
39 void(WebDataService::Handle, const WDTypedResult*)); | 41 void(WebDataService::Handle, const WDTypedResult*)); |
40 }; | 42 }; |
41 | 43 |
42 class SignalingTask : public Task { | 44 class SignalingTask : public Task { |
43 public: | 45 public: |
44 explicit SignalingTask(WaitableEvent* event) : event_(event) { | 46 explicit SignalingTask(WaitableEvent* event) : event_(event) { |
45 } | 47 } |
46 virtual void Run() { | 48 virtual void Run() { |
47 event_->Signal(); | 49 event_->Signal(); |
48 } | 50 } |
49 private: | 51 private: |
50 WaitableEvent* event_; | 52 WaitableEvent* event_; |
51 }; | 53 }; |
52 | 54 |
53 } // anonymous namespace | 55 } // anonymous namespace |
54 | 56 |
| 57 typedef std::vector<PasswordForm*> VectorOfForms; |
| 58 |
55 class PasswordStoreWinTest : public testing::Test { | 59 class PasswordStoreWinTest : public testing::Test { |
56 protected: | 60 protected: |
57 PasswordStoreWinTest() | 61 PasswordStoreWinTest() |
58 : ui_thread_(ChromeThread::UI, &message_loop_), | 62 : ui_thread_(ChromeThread::UI, &message_loop_), |
59 db_thread_(ChromeThread::DB) { | 63 db_thread_(ChromeThread::DB) { |
60 } | 64 } |
61 | 65 |
62 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created, | 66 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created, |
63 IE7PasswordInfo* info) { | 67 IE7PasswordInfo* info) { |
64 // Copied from chrome/browser/importer/importer_unittest.cc | 68 // Copied from chrome/browser/importer/importer_unittest.cc |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 MessageLoopForUI message_loop_; | 131 MessageLoopForUI message_loop_; |
128 ChromeThread ui_thread_; | 132 ChromeThread ui_thread_; |
129 ChromeThread db_thread_; // PasswordStore, WDS schedule work on this thread. | 133 ChromeThread db_thread_; // PasswordStore, WDS schedule work on this thread. |
130 | 134 |
131 scoped_ptr<LoginDatabase> login_db_; | 135 scoped_ptr<LoginDatabase> login_db_; |
132 scoped_ptr<TestingProfile> profile_; | 136 scoped_ptr<TestingProfile> profile_; |
133 scoped_refptr<WebDataService> wds_; | 137 scoped_refptr<WebDataService> wds_; |
134 ScopedTempDir temp_dir_; | 138 ScopedTempDir temp_dir_; |
135 }; | 139 }; |
136 | 140 |
| 141 ACTION(STLDeleteElements0) { |
| 142 STLDeleteContainerPointers(arg0.begin(), arg0.end()); |
| 143 } |
| 144 |
137 ACTION(QuitUIMessageLoop) { | 145 ACTION(QuitUIMessageLoop) { |
138 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 146 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
139 MessageLoop::current()->Quit(); | 147 MessageLoop::current()->Quit(); |
140 } | 148 } |
141 | 149 |
| 150 MATCHER(EmptyWDResult, "") { |
| 151 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( |
| 152 arg)->GetValue().empty(); |
| 153 } |
| 154 |
142 TEST_F(PasswordStoreWinTest, ConvertIE7Login) { | 155 TEST_F(PasswordStoreWinTest, ConvertIE7Login) { |
143 IE7PasswordInfo password_info; | 156 IE7PasswordInfo password_info; |
144 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin", | 157 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin", |
145 base::Time::FromDoubleT(1), | 158 base::Time::FromDoubleT(1), |
146 &password_info)); | 159 &password_info)); |
147 | 160 |
148 // This IE7 password will be retrieved by the GetLogins call. | 161 // This IE7 password will be retrieved by the GetLogins call. |
149 wds_->AddIE7Login(password_info); | 162 wds_->AddIE7Login(password_info); |
150 | 163 |
151 // The WDS schedules tasks to run on the DB thread so we schedule yet another | 164 // The WDS schedules tasks to run on the DB thread so we schedule yet another |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 | 330 |
318 wds_->GetIE7Login(password_info, &wds_consumer); | 331 wds_->GetIE7Login(password_info, &wds_consumer); |
319 | 332 |
320 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin | 333 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin |
321 // schedules on the DB thread and once for the one we just scheduled on the UI | 334 // schedules on the DB thread and once for the one we just scheduled on the UI |
322 // thread. | 335 // thread. |
323 MessageLoop::current()->Run(); | 336 MessageLoop::current()->Run(); |
324 MessageLoop::current()->Run(); | 337 MessageLoop::current()->Run(); |
325 | 338 |
326 STLDeleteElements(&forms); | 339 STLDeleteElements(&forms); |
327 } | 340 } |
| 341 |
| 342 TEST_F(PasswordStoreWinTest, Migration) { |
| 343 PasswordFormData autofillable_data[] = { |
| 344 { PasswordForm::SCHEME_HTML, |
| 345 "http://foo.example.com", |
| 346 "http://foo.example.com/origin", |
| 347 "http://foo.example.com/action", |
| 348 L"submit_element", |
| 349 L"username_element", |
| 350 L"password_element", |
| 351 L"username_value", |
| 352 L"password_value", |
| 353 true, false, 1 }, |
| 354 { PasswordForm::SCHEME_HTML, |
| 355 "http://bar.example.com", |
| 356 "http://bar.example.com/origin", |
| 357 "http://bar.example.com/action", |
| 358 L"submit_element", |
| 359 L"username_element", |
| 360 L"password_element", |
| 361 L"username_value", |
| 362 L"password_value", |
| 363 true, false, 2 }, |
| 364 { PasswordForm::SCHEME_HTML, |
| 365 "http://baz.example.com", |
| 366 "http://baz.example.com/origin", |
| 367 "http://baz.example.com/action", |
| 368 L"submit_element", |
| 369 L"username_element", |
| 370 L"password_element", |
| 371 L"username_value", |
| 372 L"password_value", |
| 373 true, false, 3 }, |
| 374 }; |
| 375 PasswordFormData blacklisted_data[] = { |
| 376 { PasswordForm::SCHEME_HTML, |
| 377 "http://blacklisted.example.com", |
| 378 "http://blacklisted.example.com/origin", |
| 379 "http://blacklisted.example.com/action", |
| 380 L"submit_element", |
| 381 L"username_element", |
| 382 L"password_element", |
| 383 NULL, |
| 384 NULL, |
| 385 false, false, 1 }, |
| 386 { PasswordForm::SCHEME_HTML, |
| 387 "http://blacklisted2.example.com", |
| 388 "http://blacklisted2.example.com/origin", |
| 389 "http://blacklisted2.example.com/action", |
| 390 L"submit_element", |
| 391 L"username_element", |
| 392 L"password_element", |
| 393 NULL, |
| 394 NULL, |
| 395 false, false, 2 }, |
| 396 }; |
| 397 |
| 398 VectorOfForms expected_autofillable; |
| 399 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(autofillable_data); ++i) { |
| 400 expected_autofillable.push_back( |
| 401 CreatePasswordFormFromData(autofillable_data[i])); |
| 402 } |
| 403 |
| 404 VectorOfForms expected_blacklisted; |
| 405 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) { |
| 406 expected_blacklisted.push_back( |
| 407 CreatePasswordFormFromData(blacklisted_data[i])); |
| 408 } |
| 409 |
| 410 // Populate the WDS with logins that should be migrated. |
| 411 for (VectorOfForms::iterator it = expected_autofillable.begin(); |
| 412 it != expected_autofillable.end(); ++it) { |
| 413 wds_->AddLogin(**it); |
| 414 } |
| 415 for (VectorOfForms::iterator it = expected_blacklisted.begin(); |
| 416 it != expected_blacklisted.end(); ++it) { |
| 417 wds_->AddLogin(**it); |
| 418 } |
| 419 |
| 420 // The WDS schedules tasks to run on the DB thread so we schedule yet another |
| 421 // task to notify us that it's safe to carry on with the test. |
| 422 WaitableEvent done(false, false); |
| 423 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 424 done.Wait(); |
| 425 |
| 426 // Initializing the PasswordStore should trigger a migration. |
| 427 scoped_refptr<PasswordStoreWin> store( |
| 428 new PasswordStoreWin(login_db_.release(), profile_.get(), wds_.get())); |
| 429 store->Init(); |
| 430 |
| 431 // Check that the migration preference has not been initialized; |
| 432 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( |
| 433 prefs::kLoginDatabaseMigrated)); |
| 434 |
| 435 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task |
| 436 // to signal us when it is safe to continue. |
| 437 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 438 done.Wait(); |
| 439 |
| 440 // Let the WDS callbacks proceed so the logins can be migrated. |
| 441 MessageLoop::current()->RunAllPending(); |
| 442 |
| 443 MockPasswordStoreConsumer consumer; |
| 444 |
| 445 // Make sure we quit the MessageLoop even if the test fails. |
| 446 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) |
| 447 .WillByDefault(QuitUIMessageLoop()); |
| 448 |
| 449 // The autofillable forms should have been migrated from the WDS to the login |
| 450 // database. |
| 451 EXPECT_CALL(consumer, |
| 452 OnPasswordStoreRequestDone(_, |
| 453 ContainsAllPasswordForms(expected_autofillable))) |
| 454 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); |
| 455 |
| 456 store->GetAutofillableLogins(&consumer); |
| 457 MessageLoop::current()->Run(); |
| 458 |
| 459 // The blacklisted forms should have been migrated from the WDS to the login |
| 460 // database. |
| 461 EXPECT_CALL(consumer, |
| 462 OnPasswordStoreRequestDone(_, |
| 463 ContainsAllPasswordForms(expected_blacklisted))) |
| 464 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); |
| 465 |
| 466 store->GetBlacklistLogins(&consumer); |
| 467 MessageLoop::current()->Run(); |
| 468 |
| 469 // Check that the migration updated the migrated preference. |
| 470 ASSERT_TRUE(profile_->GetPrefs()->GetBoolean(prefs::kLoginDatabaseMigrated)); |
| 471 |
| 472 MockWebDataServiceConsumer wds_consumer; |
| 473 |
| 474 // No autofillable logins should be left in the WDS. |
| 475 EXPECT_CALL(wds_consumer, |
| 476 OnWebDataServiceRequestDone(_, EmptyWDResult())); |
| 477 |
| 478 wds_->GetAutofillableLogins(&wds_consumer); |
| 479 |
| 480 // Wait for the WDS methods to execute on the DB thread. |
| 481 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 482 done.Wait(); |
| 483 |
| 484 // Handle the callback from the WDS. |
| 485 MessageLoop::current()->RunAllPending(); |
| 486 |
| 487 // Likewise, no blacklisted logins should be left in the WDS. |
| 488 EXPECT_CALL(wds_consumer, |
| 489 OnWebDataServiceRequestDone(_, EmptyWDResult())); |
| 490 |
| 491 wds_->GetBlacklistLogins(&wds_consumer); |
| 492 |
| 493 // Wait for the WDS methods to execute on the DB thread. |
| 494 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 495 done.Wait(); |
| 496 |
| 497 // Handle the callback from the WDS. |
| 498 MessageLoop::current()->RunAllPending(); |
| 499 |
| 500 STLDeleteElements(&expected_autofillable); |
| 501 STLDeleteElements(&expected_blacklisted); |
| 502 } |
OLD | NEW |