| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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.h" | 7 #include "base/stl_util.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/synchronization/waitable_event.h" | |
| 10 #include "base/time.h" | 9 #include "base/time.h" |
| 11 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 12 #include "chrome/browser/password_manager/password_form_data.h" | 11 #include "chrome/browser/password_manager/password_form_data.h" |
| 13 #include "chrome/browser/password_manager/password_store_change.h" | 12 #include "chrome/browser/password_manager/password_store_change.h" |
| 14 #include "chrome/browser/password_manager/password_store_consumer.h" | 13 #include "chrome/browser/password_manager/password_store_consumer.h" |
| 15 #include "chrome/browser/password_manager/password_store_default.h" | 14 #include "chrome/browser/password_manager/password_store_default.h" |
| 16 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
| 17 #include "chrome/browser/webdata/web_data_service.h" | 16 #include "chrome/browser/webdata/web_data_service.h" |
| 18 #include "chrome/common/chrome_notification_types.h" | 17 #include "chrome/common/chrome_notification_types.h" |
| 19 #include "chrome/common/pref_names.h" | 18 #include "chrome/common/pref_names.h" |
| 20 #include "chrome/test/base/signaling_task.h" | |
| 21 #include "chrome/test/base/testing_profile.h" | 19 #include "chrome/test/base/testing_profile.h" |
| 22 #include "content/common/notification_details.h" | 20 #include "content/common/notification_details.h" |
| 23 #include "content/common/notification_observer_mock.h" | 21 #include "content/common/notification_observer_mock.h" |
| 24 #include "content/common/notification_registrar.h" | 22 #include "content/common/notification_registrar.h" |
| 25 #include "content/common/notification_source.h" | 23 #include "content/common/notification_source.h" |
| 26 #include "testing/gmock/include/gmock/gmock.h" | 24 #include "testing/gmock/include/gmock/gmock.h" |
| 27 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 28 | 26 |
| 29 using base::WaitableEvent; | |
| 30 using testing::_; | 27 using testing::_; |
| 31 using testing::DoAll; | 28 using testing::DoAll; |
| 32 using testing::ElementsAreArray; | 29 using testing::ElementsAreArray; |
| 33 using testing::Pointee; | 30 using testing::Pointee; |
| 34 using testing::Property; | 31 using testing::Property; |
| 35 using testing::WithArg; | 32 using testing::WithArg; |
| 36 using webkit_glue::PasswordForm; | 33 using webkit_glue::PasswordForm; |
| 37 | 34 |
| 38 namespace { | 35 namespace { |
| 39 | 36 |
| 40 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 37 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
| 41 public: | 38 public: |
| 42 MOCK_METHOD2(OnPasswordStoreRequestDone, | 39 MOCK_METHOD2(OnPasswordStoreRequestDone, |
| 43 void(CancelableRequestProvider::Handle, | 40 void(CancelableRequestProvider::Handle, |
| 44 const std::vector<webkit_glue::PasswordForm*>&)); | 41 const std::vector<webkit_glue::PasswordForm*>&)); |
| 45 }; | 42 }; |
| 46 | 43 |
| 47 class MockWebDataServiceConsumer : public WebDataServiceConsumer { | 44 class MockWebDataServiceConsumer : public WebDataServiceConsumer { |
| 48 public: | 45 public: |
| 49 MOCK_METHOD2(OnWebDataServiceRequestDone, void(WebDataService::Handle, | 46 MOCK_METHOD2(OnWebDataServiceRequestDone, void(WebDataService::Handle, |
| 50 const WDTypedResult*)); | 47 const WDTypedResult*)); |
| 51 }; | 48 }; |
| 52 | 49 |
| 53 // This class will add and remove a mock notification observer from | 50 // This class will add and remove a mock notification observer from |
| 54 // the DB thread. | 51 // the DB thread. |
| 55 class DBThreadObserverHelper : | 52 class DBThreadObserverHelper : |
| 56 public base::RefCountedThreadSafe<DBThreadObserverHelper, | 53 public base::RefCountedThreadSafe<DBThreadObserverHelper, |
| 57 BrowserThread::DeleteOnDBThread> { | 54 BrowserThread::DeleteOnDBThread> { |
| 58 public: | 55 public: |
| 59 DBThreadObserverHelper() : done_event_(true, false) {} | 56 DBThreadObserverHelper() {} |
| 60 | 57 |
| 61 void Init(PasswordStore* password_store) { | 58 void Init(PasswordStore* password_store) { |
| 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 63 BrowserThread::PostTask( | 60 BrowserThread::PostTask( |
| 64 BrowserThread::DB, | 61 BrowserThread::DB, |
| 65 FROM_HERE, | 62 FROM_HERE, |
| 66 NewRunnableMethod(this, | 63 NewRunnableMethod(this, |
| 67 &DBThreadObserverHelper::AddObserverTask, | 64 &DBThreadObserverHelper::AddObserverTask, |
| 68 make_scoped_refptr(password_store))); | 65 make_scoped_refptr(password_store))); |
| 69 done_event_.Wait(); | 66 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 70 } | 67 } |
| 71 | 68 |
| 72 virtual ~DBThreadObserverHelper() { | 69 virtual ~DBThreadObserverHelper() { |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 74 registrar_.RemoveAll(); | 71 registrar_.RemoveAll(); |
| 75 } | 72 } |
| 76 | 73 |
| 77 NotificationObserverMock& observer() { | 74 NotificationObserverMock& observer() { |
| 78 return observer_; | 75 return observer_; |
| 79 } | 76 } |
| 80 | 77 |
| 81 protected: | 78 protected: |
| 82 friend class base::RefCountedThreadSafe<DBThreadObserverHelper>; | 79 friend class base::RefCountedThreadSafe<DBThreadObserverHelper>; |
| 83 | 80 |
| 84 void AddObserverTask(PasswordStore* password_store) { | 81 void AddObserverTask(PasswordStore* password_store) { |
| 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 86 registrar_.Add(&observer_, | 83 registrar_.Add(&observer_, |
| 87 chrome::NOTIFICATION_LOGINS_CHANGED, | 84 chrome::NOTIFICATION_LOGINS_CHANGED, |
| 88 Source<PasswordStore>(password_store)); | 85 Source<PasswordStore>(password_store)); |
| 89 done_event_.Signal(); | |
| 90 } | 86 } |
| 91 | 87 |
| 92 WaitableEvent done_event_; | |
| 93 NotificationRegistrar registrar_; | 88 NotificationRegistrar registrar_; |
| 94 NotificationObserverMock observer_; | 89 NotificationObserverMock observer_; |
| 95 }; | 90 }; |
| 96 | 91 |
| 97 } // anonymous namespace | 92 } // anonymous namespace |
| 98 | 93 |
| 99 typedef std::vector<PasswordForm*> VectorOfForms; | 94 typedef std::vector<PasswordForm*> VectorOfForms; |
| 100 | 95 |
| 101 class PasswordStoreDefaultTest : public testing::Test { | 96 class PasswordStoreDefaultTest : public testing::Test { |
| 102 protected: | 97 protected: |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 // Build the expected forms vector and add the forms to the store. | 174 // Build the expected forms vector and add the forms to the store. |
| 180 VectorOfForms expected_forms; | 175 VectorOfForms expected_forms; |
| 181 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) { | 176 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) { |
| 182 PasswordForm* form = CreatePasswordFormFromData(form_data[i]); | 177 PasswordForm* form = CreatePasswordFormFromData(form_data[i]); |
| 183 expected_forms.push_back(form); | 178 expected_forms.push_back(form); |
| 184 store->AddLogin(*form); | 179 store->AddLogin(*form); |
| 185 } | 180 } |
| 186 | 181 |
| 187 // The PasswordStore schedules tasks to run on the DB thread so we schedule | 182 // The PasswordStore schedules tasks to run on the DB thread so we schedule |
| 188 // yet another task to notify us that it's safe to carry on with the test. | 183 // yet another task to notify us that it's safe to carry on with the test. |
| 189 WaitableEvent done(false, false); | 184 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 190 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | |
| 191 new SignalingTask(&done)); | |
| 192 done.Wait(); | |
| 193 | 185 |
| 194 MockPasswordStoreConsumer consumer; | 186 MockPasswordStoreConsumer consumer; |
| 195 | 187 |
| 196 // Make sure we quit the MessageLoop even if the test fails. | 188 // Make sure we quit the MessageLoop even if the test fails. |
| 197 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) | 189 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) |
| 198 .WillByDefault(QuitUIMessageLoop()); | 190 .WillByDefault(QuitUIMessageLoop()); |
| 199 | 191 |
| 200 // We expect to get the same data back, even though it's not all ASCII. | 192 // We expect to get the same data back, even though it's not all ASCII. |
| 201 EXPECT_CALL(consumer, | 193 EXPECT_CALL(consumer, |
| 202 OnPasswordStoreRequestDone(_, | 194 OnPasswordStoreRequestDone(_, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 } | 266 } |
| 275 VectorOfForms expected_blacklisted; | 267 VectorOfForms expected_blacklisted; |
| 276 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) { | 268 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) { |
| 277 PasswordForm* form = CreatePasswordFormFromData(blacklisted_data[i]); | 269 PasswordForm* form = CreatePasswordFormFromData(blacklisted_data[i]); |
| 278 expected_blacklisted.push_back(form); | 270 expected_blacklisted.push_back(form); |
| 279 wds_->AddLogin(*form); | 271 wds_->AddLogin(*form); |
| 280 } | 272 } |
| 281 | 273 |
| 282 // The WDS schedules tasks to run on the DB thread so we schedule yet another | 274 // The WDS schedules tasks to run on the DB thread so we schedule yet another |
| 283 // task to notify us that it's safe to carry on with the test. | 275 // task to notify us that it's safe to carry on with the test. |
| 284 WaitableEvent done(false, false); | 276 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 285 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | |
| 286 new SignalingTask(&done)); | |
| 287 done.Wait(); | |
| 288 | 277 |
| 289 // Initializing the PasswordStore should trigger a migration. | 278 // Initializing the PasswordStore should trigger a migration. |
| 290 scoped_refptr<PasswordStore> store( | 279 scoped_refptr<PasswordStore> store( |
| 291 new PasswordStoreDefault(login_db_.release(), | 280 new PasswordStoreDefault(login_db_.release(), |
| 292 profile_.get(), wds_.get())); | 281 profile_.get(), wds_.get())); |
| 293 store->Init(); | 282 store->Init(); |
| 294 | 283 |
| 295 // Check that the migration preference has not been initialized; | 284 // Check that the migration preference has not been initialized; |
| 296 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( | 285 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( |
| 297 prefs::kLoginDatabaseMigrated)); | 286 prefs::kLoginDatabaseMigrated)); |
| 298 | 287 |
| 299 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task | 288 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task |
| 300 // to signal us when it is safe to continue. | 289 // to signal us when it is safe to continue. |
| 301 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 290 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 302 new SignalingTask(&done)); | |
| 303 done.Wait(); | |
| 304 | 291 |
| 305 // Let the WDS callbacks proceed so the logins can be migrated. | 292 // Let the WDS callbacks proceed so the logins can be migrated. |
| 306 MessageLoop::current()->RunAllPending(); | 293 MessageLoop::current()->RunAllPending(); |
| 307 | 294 |
| 308 MockPasswordStoreConsumer consumer; | 295 MockPasswordStoreConsumer consumer; |
| 309 | 296 |
| 310 // Make sure we quit the MessageLoop even if the test fails. | 297 // Make sure we quit the MessageLoop even if the test fails. |
| 311 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) | 298 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) |
| 312 .WillByDefault(QuitUIMessageLoop()); | 299 .WillByDefault(QuitUIMessageLoop()); |
| 313 | 300 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 336 | 323 |
| 337 MockWebDataServiceConsumer wds_consumer; | 324 MockWebDataServiceConsumer wds_consumer; |
| 338 | 325 |
| 339 // No autofillable logins should be left in the WDS. | 326 // No autofillable logins should be left in the WDS. |
| 340 EXPECT_CALL(wds_consumer, | 327 EXPECT_CALL(wds_consumer, |
| 341 OnWebDataServiceRequestDone(_, EmptyWDResult())); | 328 OnWebDataServiceRequestDone(_, EmptyWDResult())); |
| 342 | 329 |
| 343 wds_->GetAutofillableLogins(&wds_consumer); | 330 wds_->GetAutofillableLogins(&wds_consumer); |
| 344 | 331 |
| 345 // Wait for the WDS methods to execute on the DB thread. | 332 // Wait for the WDS methods to execute on the DB thread. |
| 346 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 333 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 347 new SignalingTask(&done)); | |
| 348 done.Wait(); | |
| 349 | 334 |
| 350 // Handle the callback from the WDS. | 335 // Handle the callback from the WDS. |
| 351 MessageLoop::current()->RunAllPending(); | 336 MessageLoop::current()->RunAllPending(); |
| 352 | 337 |
| 353 // Likewise, no blacklisted logins should be left in the WDS. | 338 // Likewise, no blacklisted logins should be left in the WDS. |
| 354 EXPECT_CALL(wds_consumer, | 339 EXPECT_CALL(wds_consumer, |
| 355 OnWebDataServiceRequestDone(_, EmptyWDResult())); | 340 OnWebDataServiceRequestDone(_, EmptyWDResult())); |
| 356 | 341 |
| 357 wds_->GetBlacklistLogins(&wds_consumer); | 342 wds_->GetBlacklistLogins(&wds_consumer); |
| 358 | 343 |
| 359 // Wait for the WDS methods to execute on the DB thread. | 344 // Wait for the WDS methods to execute on the DB thread. |
| 360 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 345 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 361 new SignalingTask(&done)); | |
| 362 done.Wait(); | |
| 363 | 346 |
| 364 // Handle the callback from the WDS. | 347 // Handle the callback from the WDS. |
| 365 MessageLoop::current()->RunAllPending(); | 348 MessageLoop::current()->RunAllPending(); |
| 366 | 349 |
| 367 STLDeleteElements(&expected_autofillable); | 350 STLDeleteElements(&expected_autofillable); |
| 368 STLDeleteElements(&expected_blacklisted); | 351 STLDeleteElements(&expected_blacklisted); |
| 369 | 352 |
| 370 store->Shutdown(); | 353 store->Shutdown(); |
| 371 } | 354 } |
| 372 | 355 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 387 // Build the expected forms vector and populate the WDS with logins. | 370 // Build the expected forms vector and populate the WDS with logins. |
| 388 VectorOfForms unexpected_autofillable; | 371 VectorOfForms unexpected_autofillable; |
| 389 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(wds_data); ++i) { | 372 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(wds_data); ++i) { |
| 390 PasswordForm* form = CreatePasswordFormFromData(wds_data[i]); | 373 PasswordForm* form = CreatePasswordFormFromData(wds_data[i]); |
| 391 unexpected_autofillable.push_back(form); | 374 unexpected_autofillable.push_back(form); |
| 392 wds_->AddLogin(*form); | 375 wds_->AddLogin(*form); |
| 393 } | 376 } |
| 394 | 377 |
| 395 // The WDS schedules tasks to run on the DB thread so we schedule yet another | 378 // The WDS schedules tasks to run on the DB thread so we schedule yet another |
| 396 // task to notify us that it's safe to carry on with the test. | 379 // task to notify us that it's safe to carry on with the test. |
| 397 WaitableEvent done(false, false); | 380 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 398 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | |
| 399 new SignalingTask(&done)); | |
| 400 done.Wait(); | |
| 401 | 381 |
| 402 // Pretend that the migration has already taken place. | 382 // Pretend that the migration has already taken place. |
| 403 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, | 383 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, |
| 404 true, | 384 true, |
| 405 PrefService::UNSYNCABLE_PREF); | 385 PrefService::UNSYNCABLE_PREF); |
| 406 | 386 |
| 407 // Initializing the PasswordStore shouldn't trigger a migration. | 387 // Initializing the PasswordStore shouldn't trigger a migration. |
| 408 scoped_refptr<PasswordStore> store( | 388 scoped_refptr<PasswordStore> store( |
| 409 new PasswordStoreDefault(login_db_.release(), profile_.get(), | 389 new PasswordStoreDefault(login_db_.release(), profile_.get(), |
| 410 wds_.get())); | 390 wds_.get())); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 Source<PasswordStore>(store), | 447 Source<PasswordStore>(store), |
| 468 Property(&Details<const PasswordStoreChangeList>::ptr, | 448 Property(&Details<const PasswordStoreChangeList>::ptr, |
| 469 Pointee(ElementsAreArray( | 449 Pointee(ElementsAreArray( |
| 470 expected_add_changes))))); | 450 expected_add_changes))))); |
| 471 | 451 |
| 472 // Adding a login should trigger a notification. | 452 // Adding a login should trigger a notification. |
| 473 store->AddLogin(*form); | 453 store->AddLogin(*form); |
| 474 | 454 |
| 475 // The PasswordStore schedules tasks to run on the DB thread so we schedule | 455 // The PasswordStore schedules tasks to run on the DB thread so we schedule |
| 476 // yet another task to notify us that it's safe to carry on with the test. | 456 // yet another task to notify us that it's safe to carry on with the test. |
| 477 WaitableEvent done(false, false); | 457 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 478 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | |
| 479 new SignalingTask(&done)); | |
| 480 done.Wait(); | |
| 481 | 458 |
| 482 // Change the password. | 459 // Change the password. |
| 483 form->password_value = WideToUTF16(L"a different password"); | 460 form->password_value = WideToUTF16(L"a different password"); |
| 484 | 461 |
| 485 const PasswordStoreChange expected_update_changes[] = { | 462 const PasswordStoreChange expected_update_changes[] = { |
| 486 PasswordStoreChange(PasswordStoreChange::UPDATE, *form), | 463 PasswordStoreChange(PasswordStoreChange::UPDATE, *form), |
| 487 }; | 464 }; |
| 488 | 465 |
| 489 EXPECT_CALL(helper->observer(), | 466 EXPECT_CALL(helper->observer(), |
| 490 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED), | 467 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED), |
| 491 Source<PasswordStore>(store), | 468 Source<PasswordStore>(store), |
| 492 Property(&Details<const PasswordStoreChangeList>::ptr, | 469 Property(&Details<const PasswordStoreChangeList>::ptr, |
| 493 Pointee(ElementsAreArray( | 470 Pointee(ElementsAreArray( |
| 494 expected_update_changes))))); | 471 expected_update_changes))))); |
| 495 | 472 |
| 496 // Updating the login with the new password should trigger a notification. | 473 // Updating the login with the new password should trigger a notification. |
| 497 store->UpdateLogin(*form); | 474 store->UpdateLogin(*form); |
| 498 | 475 |
| 499 // Wait for PasswordStore to send the notification. | 476 // Wait for PasswordStore to send the notification. |
| 500 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 477 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 501 new SignalingTask(&done)); | |
| 502 done.Wait(); | |
| 503 | 478 |
| 504 const PasswordStoreChange expected_delete_changes[] = { | 479 const PasswordStoreChange expected_delete_changes[] = { |
| 505 PasswordStoreChange(PasswordStoreChange::REMOVE, *form), | 480 PasswordStoreChange(PasswordStoreChange::REMOVE, *form), |
| 506 }; | 481 }; |
| 507 | 482 |
| 508 EXPECT_CALL(helper->observer(), | 483 EXPECT_CALL(helper->observer(), |
| 509 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED), | 484 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED), |
| 510 Source<PasswordStore>(store), | 485 Source<PasswordStore>(store), |
| 511 Property(&Details<const PasswordStoreChangeList>::ptr, | 486 Property(&Details<const PasswordStoreChangeList>::ptr, |
| 512 Pointee(ElementsAreArray( | 487 Pointee(ElementsAreArray( |
| 513 expected_delete_changes))))); | 488 expected_delete_changes))))); |
| 514 | 489 |
| 515 // Deleting the login should trigger a notification. | 490 // Deleting the login should trigger a notification. |
| 516 store->RemoveLogin(*form); | 491 store->RemoveLogin(*form); |
| 517 | 492 |
| 518 // Wait for PasswordStore to send the notification. | 493 // Wait for PasswordStore to send the notification. |
| 519 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 494 CHECK(BrowserThread::WaitForPendingTasksOn(BrowserThread::DB)); |
| 520 new SignalingTask(&done)); | |
| 521 done.Wait(); | |
| 522 | 495 |
| 523 store->Shutdown(); | 496 store->Shutdown(); |
| 524 } | 497 } |
| OLD | NEW |