| Index: components/password_manager/core/browser/form_fetcher_impl_unittest.cc
|
| diff --git a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
|
| index 90c36a90dbf9ad13e8a29391c28639b217517182..6373db3549eeca91c6291d9e45abb3fcf3f13a1e 100644
|
| --- a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
|
| +++ b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
|
| @@ -44,6 +44,12 @@ namespace password_manager {
|
|
|
| namespace {
|
|
|
| +const char kTestHttpRealm[] = "http://accounts.google.com/";
|
| +const char kTestHttpURL[] = "http://accounts.google.com/a/LoginAuth";
|
| +
|
| +const char kTestHttpsRealm[] = "https://accounts.google.com/";
|
| +const char kTestHttpsURL[] = "https://accounts.google.com/a/LoginAuth";
|
| +
|
| class MockConsumer : public FormFetcher::Consumer {
|
| public:
|
| MOCK_METHOD2(ProcessMatches,
|
| @@ -128,7 +134,7 @@ PasswordForm CreateHTTPNonFederated() {
|
| PasswordForm CreateFederated() {
|
| PasswordForm form = CreateNonFederated();
|
| form.password_value.clear();
|
| - form.federation_origin = url::Origin(GURL("https://accounts.google.com/"));
|
| + form.federation_origin = url::Origin(GURL(kTestHttpsRealm));
|
| return form;
|
| }
|
|
|
| @@ -162,13 +168,14 @@ class FormFetcherImplTest : public testing::Test {
|
| public:
|
| FormFetcherImplTest()
|
| : form_digest_(PasswordForm::SCHEME_HTML,
|
| - "http://accounts.google.com",
|
| - GURL("http://accounts.google.com/a/LoginAuth")) {
|
| + kTestHttpRealm,
|
| + GURL(kTestHttpURL)) {
|
| mock_store_ = new MockPasswordStore();
|
| client_.set_store(mock_store_.get());
|
|
|
| form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
|
| - form_digest_, &client_, /* should_migrate_http_passwords */ false);
|
| + form_digest_, &client_, false /* should_migrate_http_passwords */,
|
| + false /* should_query_suppressed_https_forms */);
|
| }
|
|
|
| ~FormFetcherImplTest() override { mock_store_->ShutdownOnUIThread(); }
|
| @@ -186,6 +193,52 @@ class FormFetcherImplTest : public testing::Test {
|
| testing::Mock::VerifyAndClearExpectations(mock_store_.get());
|
| }
|
|
|
| + void RecreateFormFetcherWithQueryingSuppressedHTTPSForms() {
|
| + form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
|
| + form_digest_, &client_, false /* should_migrate_http_passwords */,
|
| + true /* should_query_suppressed_https_forms */);
|
| + EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
|
| + form_fetcher_->AddConsumer(&consumer_);
|
| + testing::Mock::VerifyAndClearExpectations(&consumer_);
|
| + }
|
| +
|
| + // Simulates a call to Fetch(), and supplies |simulated_matches| as the
|
| + // PasswordStore results. Expects that this will trigger the querying of
|
| + // suppressed HTTPS forms by means of a GetLogins call being issued against
|
| + // the |expected_form_digest|. Call CompleteQueryingSuppressedHTTPSForms with
|
| + // the emitted |consumer_ptr| to complete the query.
|
| + void SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + const std::vector<PasswordForm>& simulated_http_matches,
|
| + const PasswordStore::FormDigest expected_form_digest,
|
| + base::WeakPtr<PasswordStoreConsumer>* consumer_ptr /* out */) {
|
| + ASSERT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| +
|
| + Fetch();
|
| +
|
| + EXPECT_CALL(*mock_store_, GetLogins(expected_form_digest, _))
|
| + .WillOnce(::testing::WithArg<1>(GetAndAssignWeakPtr(consumer_ptr)));
|
| + const size_t num_matches = simulated_http_matches.size();
|
| + EXPECT_CALL(consumer_, ProcessMatches(::testing::SizeIs(num_matches), 0u));
|
| +
|
| + form_fetcher_->OnGetPasswordStoreResults(
|
| + MakeResults(simulated_http_matches));
|
| +
|
| + ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&consumer_));
|
| + ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(mock_store_.get()));
|
| + ASSERT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| + ASSERT_TRUE(*consumer_ptr);
|
| + }
|
| +
|
| + void CompleteQueryingSuppressedHTTPSForms(
|
| + const std::vector<PasswordForm>& simulated_suppressed_https_forms,
|
| + base::WeakPtr<PasswordStoreConsumer> consumer_ptr) {
|
| + ASSERT_TRUE(consumer_ptr);
|
| + ASSERT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| + consumer_ptr->OnGetPasswordStoreResults(
|
| + MakeResults(simulated_suppressed_https_forms));
|
| + ASSERT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| + }
|
| +
|
| base::MessageLoop message_loop_; // Used by mock_store_.
|
| PasswordStore::FormDigest form_digest_;
|
| std::unique_ptr<FormFetcherImpl> form_fetcher_;
|
| @@ -399,7 +452,8 @@ TEST_F(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
|
| // A new form fetcher is created to be able to set the form digest and
|
| // migration flag.
|
| form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
|
| - form_digest_, &client_, /* should_migrate_http_passwords */ true);
|
| + form_digest_, &client_, true /* should_migrate_http_passwords */,
|
| + false /* should_query_suppressed_https_forms */);
|
| EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
|
| form_fetcher_->AddConsumer(&consumer_);
|
|
|
| @@ -441,7 +495,8 @@ TEST_F(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
|
| // A new form fetcher is created to be able to set the form digest and
|
| // migration flag.
|
| form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
|
| - form_digest_, &client_, /* should_migrate_http_passwords */ true);
|
| + form_digest_, &client_, true /* should_migrate_http_passwords */,
|
| + false /* should_query_suppressed_https_forms */);
|
| EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
|
| form_fetcher_->AddConsumer(&consumer_);
|
|
|
| @@ -510,7 +565,8 @@ TEST_F(FormFetcherImplTest, StateIsWaitingDuringMigration) {
|
| // A new form fetcher is created to be able to set the form digest and
|
| // migration flag.
|
| form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
|
| - form_digest_, &client_, /* should_migrate_http_passwords */ true);
|
| + form_digest_, &client_, true /* should_migrate_http_passwords */,
|
| + false /* should_query_suppressed_https_forms */);
|
|
|
| PasswordForm https_form = CreateNonFederated();
|
|
|
| @@ -551,6 +607,149 @@ TEST_F(FormFetcherImplTest, StateIsWaitingDuringMigration) {
|
| EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| }
|
|
|
| +TEST_F(FormFetcherImplTest, SuppressedHTTPSForms_QueriedForHTTPOrigins) {
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| +
|
| + // The matching PasswordStore results coming in should trigger another
|
| + // GetLogins request to fetcht the suppressed HTTPS forms.
|
| + const PasswordStore::FormDigest https_version_of_form_digest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + const PasswordForm matching_http_form = CreateHTTPNonFederated();
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr = nullptr;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + {matching_http_form}, https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| +
|
| + EXPECT_FALSE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(), IsEmpty());
|
| +
|
| + const PasswordForm suppressed_https_form1 = CreateNonFederated();
|
| + const PasswordForm suppressed_https_form2 = CreateFederated();
|
| + ASSERT_NO_FATAL_FAILURE(CompleteQueryingSuppressedHTTPSForms(
|
| + {suppressed_https_form1, suppressed_https_form2},
|
| + https_form_fetcher_ptr));
|
| +
|
| + EXPECT_TRUE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(),
|
| + UnorderedElementsAre(Pointee(suppressed_https_form1),
|
| + Pointee(suppressed_https_form2)));
|
| +}
|
| +
|
| +TEST_F(FormFetcherImplTest, SuppressedHTTPSForms_RequeriedOnRefetch) {
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| +
|
| + const PasswordStore::FormDigest https_version_of_form_digest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr = nullptr;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| + ASSERT_NO_FATAL_FAILURE(CompleteQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_form_fetcher_ptr));
|
| +
|
| + // Another call to Fetch() should refetch the list of suppressed HTTPS
|
| + // credentials as well.
|
| + const PasswordForm suppressed_https_form = CreateNonFederated();
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| + ASSERT_NO_FATAL_FAILURE(CompleteQueryingSuppressedHTTPSForms(
|
| + {suppressed_https_form}, https_form_fetcher_ptr));
|
| +
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(),
|
| + UnorderedElementsAre(Pointee(suppressed_https_form)));
|
| +}
|
| +
|
| +TEST_F(FormFetcherImplTest, SuppressedHTTPSForms_NeverWiped) {
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| +
|
| + const PasswordStore::FormDigest https_version_of_form_digest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + const PasswordForm suppressed_https_form = CreateNonFederated();
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr = nullptr;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| + ASSERT_NO_FATAL_FAILURE(CompleteQueryingSuppressedHTTPSForms(
|
| + {suppressed_https_form}, https_form_fetcher_ptr));
|
| +
|
| + // Ensure that calling Fetch() does not wipe (even temporarily) the previously
|
| + // fetched list of suppressed HTTPS credentials. Stale is better than nothing.
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| +
|
| + EXPECT_TRUE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(),
|
| + UnorderedElementsAre(Pointee(suppressed_https_form)));
|
| +}
|
| +
|
| +TEST_F(FormFetcherImplTest,
|
| + SuppressedHTTPSForms_FormFetcherDestroyedWhileQuerying) {
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| +
|
| + const PasswordStore::FormDigest https_version_of_form_digest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr = nullptr;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr));
|
| +
|
| + EXPECT_FALSE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| +
|
| + // Destroy FormFetcher while SuppressedHTTPSFormFetcher is busy.
|
| + form_fetcher_.reset();
|
| +}
|
| +
|
| +// Exercise the scenario where querying the suppressed HTTPS logins takes so
|
| +// long that in the meantime there is another call to Fetch(), which completes,
|
| +// and triggers fetching HTTPS suppressed forms yet again. In this case, the
|
| +// first SuppressedHTTPSFormFetcher is destroyed and its query cancelled.
|
| +TEST_F(FormFetcherImplTest, SuppressedHTTPSForms_SimultaneousQueries) {
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| +
|
| + const PasswordStore::FormDigest https_version_of_form_digest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr1;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr1));
|
| +
|
| + base::WeakPtr<PasswordStoreConsumer> https_form_fetcher_ptr2;
|
| + ASSERT_NO_FATAL_FAILURE(SimulateFetchAndExpectQueryingSuppressedHTTPSForms(
|
| + std::vector<PasswordForm>(), https_version_of_form_digest,
|
| + &https_form_fetcher_ptr2));
|
| +
|
| + EXPECT_FALSE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(), IsEmpty());
|
| + EXPECT_FALSE(https_form_fetcher_ptr1);
|
| + ASSERT_TRUE(https_form_fetcher_ptr2);
|
| +
|
| + const PasswordForm suppressed_https_form = CreateNonFederated();
|
| + ASSERT_NO_FATAL_FAILURE(CompleteQueryingSuppressedHTTPSForms(
|
| + {suppressed_https_form}, https_form_fetcher_ptr2));
|
| +
|
| + EXPECT_TRUE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| + EXPECT_THAT(form_fetcher_->GetSuppressedHTTPSForms(),
|
| + UnorderedElementsAre(Pointee(suppressed_https_form)));
|
| +}
|
| +
|
| +TEST_F(FormFetcherImplTest, SuppressedHTTPSForms_NotQueriedForHTTPSOrigins) {
|
| + form_digest_ = PasswordStore::FormDigest(
|
| + PasswordForm::SCHEME_HTML, kTestHttpsRealm, GURL(kTestHttpsURL));
|
| + RecreateFormFetcherWithQueryingSuppressedHTTPSForms();
|
| + Fetch();
|
| +
|
| + EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
|
| + EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
|
| +
|
| + form_fetcher_->OnGetPasswordStoreResults(
|
| + MakeResults(std::vector<PasswordForm>()));
|
| +
|
| + EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
|
| + EXPECT_FALSE(form_fetcher_->DidCompleteQueryingSuppressedHTTPSForms());
|
| +}
|
| +
|
| // Cloning a FormFetcherImpl with empty results should result in an
|
| // instance with empty results.
|
| TEST_F(FormFetcherImplTest, Clone_EmptyResults) {
|
| @@ -564,6 +763,7 @@ TEST_F(FormFetcherImplTest, Clone_EmptyResults) {
|
| EXPECT_EQ(FormFetcher::State::NOT_WAITING, clone->GetState());
|
| EXPECT_THAT(clone->GetInteractionsStats(), IsEmpty());
|
| EXPECT_THAT(clone->GetFederatedMatches(), IsEmpty());
|
| + EXPECT_THAT(clone->GetSuppressedHTTPSForms(), IsEmpty());
|
| MockConsumer consumer;
|
| EXPECT_CALL(consumer, ProcessMatches(IsEmpty(), 0u));
|
| clone->AddConsumer(&consumer);
|
| @@ -615,6 +815,19 @@ TEST_F(FormFetcherImplTest, Clone_Stats) {
|
| EXPECT_EQ(1u, clone->GetInteractionsStats().size());
|
| }
|
|
|
| +// Cloning a FormFetcherImpl with some suppressed HTTPS credentials should
|
| +// result in an instance with the same suppressed credentials.
|
| +TEST_F(FormFetcherImplTest, Clone_SuppressedHTTPSCredentials) {
|
| + Fetch();
|
| + form_fetcher_->OnGetPasswordStoreResults(
|
| + std::vector<std::unique_ptr<PasswordForm>>());
|
| + form_fetcher_->ProcessSuppressedHTTPSForms(
|
| + MakeResults({CreateNonFederated()}));
|
| +
|
| + auto clone = form_fetcher_->Clone();
|
| + EXPECT_EQ(1u, clone->GetSuppressedHTTPSForms().size());
|
| +}
|
| +
|
| // Check that removing consumers stops them from receiving store updates.
|
| TEST_F(FormFetcherImplTest, RemoveConsumer) {
|
| Fetch();
|
|
|