Index: components/password_manager/core/browser/affiliated_match_helper_unittest.cc |
diff --git a/components/password_manager/core/browser/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/affiliated_match_helper_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..80e169e3ceadd21f70047a237a01b0d1c1cabc86 |
--- /dev/null |
+++ b/components/password_manager/core/browser/affiliated_match_helper_unittest.cc |
@@ -0,0 +1,630 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/password_manager/core/browser/affiliated_match_helper.h" |
+ |
+#include <stddef.h> |
+ |
+#include <memory> |
+#include <utility> |
+ |
+#include "base/macros.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "base/test/scoped_mock_time_message_loop_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "components/password_manager/core/browser/affiliation_service.h" |
+#include "components/password_manager/core/browser/affiliation_utils.h" |
+#include "components/password_manager/core/browser/test_password_store.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace password_manager { |
+ |
+namespace { |
+ |
+using StrategyOnCacheMiss = AffiliationService::StrategyOnCacheMiss; |
+ |
+class MockAffiliationService : public testing::StrictMock<AffiliationService> { |
+ public: |
+ MockAffiliationService() : testing::StrictMock<AffiliationService>(nullptr) { |
+ testing::DefaultValue<AffiliatedFacets>::Set(AffiliatedFacets()); |
+ } |
+ |
+ ~MockAffiliationService() override {} |
+ |
+ MOCK_METHOD2(OnGetAffiliationsCalled, |
+ AffiliatedFacets(const FacetURI&, StrategyOnCacheMiss)); |
+ MOCK_METHOD2(Prefetch, void(const FacetURI&, const base::Time&)); |
+ MOCK_METHOD2(CancelPrefetch, void(const FacetURI&, const base::Time&)); |
+ MOCK_METHOD1(TrimCacheForFacet, void(const FacetURI&)); |
+ |
+ void GetAffiliations(const FacetURI& facet_uri, |
+ StrategyOnCacheMiss cache_miss_strategy, |
+ const ResultCallback& result_callback) override { |
+ AffiliatedFacets affiliation = |
+ OnGetAffiliationsCalled(facet_uri, cache_miss_strategy); |
+ result_callback.Run(affiliation, !affiliation.empty()); |
+ } |
+ |
+ void ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ const FacetURI& expected_facet_uri, |
+ StrategyOnCacheMiss expected_cache_miss_strategy, |
+ const AffiliatedFacets& affiliations_to_return) { |
+ EXPECT_CALL(*this, OnGetAffiliationsCalled(expected_facet_uri, |
+ expected_cache_miss_strategy)) |
+ .WillOnce(testing::Return(affiliations_to_return)); |
+ } |
+ |
+ void ExpectCallToGetAffiliationsAndEmulateFailure( |
+ const FacetURI& expected_facet_uri, |
+ StrategyOnCacheMiss expected_cache_miss_strategy) { |
+ EXPECT_CALL(*this, OnGetAffiliationsCalled(expected_facet_uri, |
+ expected_cache_miss_strategy)) |
+ .WillOnce(testing::Return(std::vector<FacetURI>())); |
+ } |
+ |
+ void ExpectCallToPrefetch(const char* expected_facet_uri_spec) { |
+ EXPECT_CALL(*this, |
+ Prefetch(FacetURI::FromCanonicalSpec(expected_facet_uri_spec), |
+ base::Time::Max())).RetiresOnSaturation(); |
+ } |
+ |
+ void ExpectCallToCancelPrefetch(const char* expected_facet_uri_spec) { |
+ EXPECT_CALL(*this, CancelPrefetch( |
+ FacetURI::FromCanonicalSpec(expected_facet_uri_spec), |
+ base::Time::Max())).RetiresOnSaturation(); |
+ } |
+ |
+ void ExpectCallToTrimCacheForFacet(const char* expected_facet_uri_spec) { |
+ EXPECT_CALL(*this, TrimCacheForFacet(FacetURI::FromCanonicalSpec( |
+ expected_facet_uri_spec))).RetiresOnSaturation(); |
+ } |
+ |
+ private: |
+ DISALLOW_ASSIGN(MockAffiliationService); |
+}; |
+ |
+const char kTestWebFacetURIAlpha1[] = "https://one.alpha.example.com"; |
+const char kTestWebFacetURIAlpha2[] = "https://two.alpha.example.com"; |
+const char kTestAndroidFacetURIAlpha3[] = |
+ "android://hash@com.example.alpha.android"; |
+const char kTestWebRealmAlpha1[] = "https://one.alpha.example.com/"; |
+const char kTestWebRealmAlpha2[] = "https://two.alpha.example.com/"; |
+const char kTestAndroidRealmAlpha3[] = |
+ "android://hash@com.example.alpha.android/"; |
+ |
+const char kTestWebFacetURIBeta1[] = "https://one.beta.example.com"; |
+const char kTestAndroidFacetURIBeta2[] = |
+ "android://hash@com.example.beta.android"; |
+const char kTestAndroidFacetURIBeta3[] = |
+ "android://hash@com.yetanother.beta.android"; |
+const char kTestWebRealmBeta1[] = "https://one.beta.example.com/"; |
+const char kTestAndroidRealmBeta2[] = |
+ "android://hash@com.example.beta.android/"; |
+const char kTestAndroidRealmBeta3[] = |
+ "android://hash@com.yetanother.beta.android/"; |
+ |
+const char kTestAndroidFacetURIGamma[] = |
+ "android://hash@com.example.gamma.android"; |
+const char kTestAndroidRealmGamma[] = |
+ "android://hash@com.example.gamma.android"; |
+ |
+const char kTestUsername[] = "JohnDoe"; |
+const char kTestPassword[] = "secret"; |
+ |
+AffiliatedFacets GetTestEquivalenceClassAlpha() { |
+ AffiliatedFacets affiliated_facets; |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1)); |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha2)); |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3)); |
+ return affiliated_facets; |
+} |
+ |
+AffiliatedFacets GetTestEquivalenceClassBeta() { |
+ AffiliatedFacets affiliated_facets; |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1)); |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2)); |
+ affiliated_facets.push_back( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3)); |
+ return affiliated_facets; |
+} |
+ |
+autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) { |
+ autofill::PasswordForm form; |
+ form.scheme = autofill::PasswordForm::SCHEME_HTML; |
+ form.signon_realm = signon_realm; |
+ form.username_value = base::ASCIIToUTF16(kTestUsername); |
+ form.password_value = base::ASCIIToUTF16(kTestPassword); |
+ return form; |
+} |
+ |
+autofill::PasswordForm GetTestBlacklistedAndroidCredentials( |
+ const char* signon_realm) { |
+ autofill::PasswordForm form = GetTestAndroidCredentials(signon_realm); |
+ form.blacklisted_by_user = true; |
+ return form; |
+} |
+ |
+PasswordStore::FormDigest GetTestObservedWebForm(const char* signon_realm, |
+ const char* origin) { |
+ return {autofill::PasswordForm::SCHEME_HTML, signon_realm, |
+ origin ? GURL(origin) : GURL()}; |
+} |
+ |
+} // namespace |
+ |
+class AffiliatedMatchHelperTest : public testing::Test { |
+ public: |
+ AffiliatedMatchHelperTest() |
+ : expecting_result_callback_(false), mock_affiliation_service_(nullptr) {} |
+ ~AffiliatedMatchHelperTest() override {} |
+ |
+ protected: |
+ void RunDeferredInitialization() { |
+ mock_time_task_runner_->RunUntilIdle(); |
+ ASSERT_EQ(AffiliatedMatchHelper::kInitializationDelayOnStartup, |
+ mock_time_task_runner_->NextPendingTaskDelay()); |
+ mock_time_task_runner_->FastForwardBy( |
+ AffiliatedMatchHelper::kInitializationDelayOnStartup); |
+ } |
+ |
+ void RunUntilIdle() { |
+ // TODO(gab): Add support for base::RunLoop().RunUntilIdle() in scope of |
+ // ScopedMockTimeMessageLoopTaskRunner and use it instead of this helper |
+ // method. |
+ mock_time_task_runner_->RunUntilIdle(); |
+ } |
+ |
+ void AddLogin(const autofill::PasswordForm& form) { |
+ password_store_->AddLogin(form); |
+ RunUntilIdle(); |
+ } |
+ |
+ void UpdateLoginWithPrimaryKey( |
+ const autofill::PasswordForm& new_form, |
+ const autofill::PasswordForm& old_primary_key) { |
+ password_store_->UpdateLoginWithPrimaryKey(new_form, old_primary_key); |
+ RunUntilIdle(); |
+ } |
+ |
+ void RemoveLogin(const autofill::PasswordForm& form) { |
+ password_store_->RemoveLogin(form); |
+ RunUntilIdle(); |
+ } |
+ |
+ void AddAndroidAndNonAndroidTestLogins() { |
+ AddLogin(GetTestAndroidCredentials(kTestAndroidRealmAlpha3)); |
+ AddLogin(GetTestAndroidCredentials(kTestAndroidRealmBeta2)); |
+ AddLogin(GetTestBlacklistedAndroidCredentials(kTestAndroidRealmBeta3)); |
+ AddLogin(GetTestAndroidCredentials(kTestAndroidRealmGamma)); |
+ |
+ AddLogin(GetTestAndroidCredentials(kTestWebRealmAlpha1)); |
+ AddLogin(GetTestAndroidCredentials(kTestWebRealmAlpha2)); |
+ } |
+ |
+ void RemoveAndroidAndNonAndroidTestLogins() { |
+ RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmAlpha3)); |
+ RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmBeta2)); |
+ RemoveLogin(GetTestBlacklistedAndroidCredentials(kTestAndroidRealmBeta3)); |
+ RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmGamma)); |
+ |
+ RemoveLogin(GetTestAndroidCredentials(kTestWebRealmAlpha1)); |
+ RemoveLogin(GetTestAndroidCredentials(kTestWebRealmAlpha2)); |
+ } |
+ |
+ void ExpectPrefetchForAndroidTestLogins() { |
+ mock_affiliation_service()->ExpectCallToPrefetch( |
+ kTestAndroidFacetURIAlpha3); |
+ mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIBeta2); |
+ mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIBeta3); |
+ mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIGamma); |
+ } |
+ |
+ void ExpectCancelPrefetchForAndroidTestLogins() { |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIAlpha3); |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIBeta2); |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIBeta3); |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIGamma); |
+ } |
+ |
+ void ExpectTrimCacheForAndroidTestLogins() { |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIAlpha3); |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIBeta2); |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIBeta3); |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIGamma); |
+ } |
+ |
+ std::vector<std::string> GetAffiliatedAndroidRealms( |
+ const PasswordStore::FormDigest& observed_form) { |
+ expecting_result_callback_ = true; |
+ match_helper()->GetAffiliatedAndroidRealms( |
+ observed_form, |
+ base::Bind(&AffiliatedMatchHelperTest::OnAffiliatedRealmsCallback, |
+ base::Unretained(this))); |
+ RunUntilIdle(); |
+ EXPECT_FALSE(expecting_result_callback_); |
+ return last_result_realms_; |
+ } |
+ |
+ std::vector<std::string> GetAffiliatedWebRealms( |
+ const PasswordStore::FormDigest& android_form) { |
+ expecting_result_callback_ = true; |
+ match_helper()->GetAffiliatedWebRealms( |
+ android_form, |
+ base::Bind(&AffiliatedMatchHelperTest::OnAffiliatedRealmsCallback, |
+ base::Unretained(this))); |
+ RunUntilIdle(); |
+ EXPECT_FALSE(expecting_result_callback_); |
+ return last_result_realms_; |
+ } |
+ |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> |
+ InjectAffiliatedWebRealms( |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) { |
+ expecting_result_callback_ = true; |
+ match_helper()->InjectAffiliatedWebRealms( |
+ std::move(forms), |
+ base::Bind(&AffiliatedMatchHelperTest::OnFormsCallback, |
+ base::Unretained(this))); |
+ RunUntilIdle(); |
+ EXPECT_FALSE(expecting_result_callback_); |
+ return std::move(last_result_forms_); |
+ } |
+ |
+ void DestroyMatchHelper() { match_helper_.reset(); } |
+ |
+ TestPasswordStore* password_store() { return password_store_.get(); } |
+ |
+ MockAffiliationService* mock_affiliation_service() { |
+ return mock_affiliation_service_; |
+ } |
+ |
+ AffiliatedMatchHelper* match_helper() { return match_helper_.get(); } |
+ |
+ private: |
+ void OnAffiliatedRealmsCallback( |
+ const std::vector<std::string>& affiliated_realms) { |
+ EXPECT_TRUE(expecting_result_callback_); |
+ expecting_result_callback_ = false; |
+ last_result_realms_ = affiliated_realms; |
+ } |
+ |
+ void OnFormsCallback( |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) { |
+ EXPECT_TRUE(expecting_result_callback_); |
+ expecting_result_callback_ = false; |
+ last_result_forms_.swap(forms); |
+ } |
+ |
+ // testing::Test: |
+ void SetUp() override { |
+ std::unique_ptr<MockAffiliationService> service( |
+ new MockAffiliationService()); |
+ mock_affiliation_service_ = service.get(); |
+ |
+ password_store_ = new TestPasswordStore; |
+ |
+ match_helper_.reset( |
+ new AffiliatedMatchHelper(password_store_.get(), std::move(service))); |
+ } |
+ |
+ void TearDown() override { |
+ match_helper_.reset(); |
+ password_store_->ShutdownOnUIThread(); |
+ password_store_ = nullptr; |
+ } |
+ |
+ base::MessageLoop message_loop_; |
+ base::ScopedMockTimeMessageLoopTaskRunner mock_time_task_runner_; |
+ |
+ std::vector<std::string> last_result_realms_; |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> last_result_forms_; |
+ bool expecting_result_callback_; |
+ |
+ scoped_refptr<TestPasswordStore> password_store_; |
+ std::unique_ptr<AffiliatedMatchHelper> match_helper_; |
+ |
+ // Owned by |match_helper_|. |
+ MockAffiliationService* mock_affiliation_service_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AffiliatedMatchHelperTest); |
+}; |
+ |
+// GetAffiliatedAndroidRealm* tests verify that GetAffiliatedAndroidRealms() |
+// returns the realms of affiliated Android applications, but only Android |
+// applications, and only if the observed form is a secure HTML login form. |
+ |
+TEST_F(AffiliatedMatchHelperTest, GetAffiliatedAndroidRealmsYieldsResults) { |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1), |
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta()); |
+ EXPECT_THAT(GetAffiliatedAndroidRealms( |
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)), |
+ testing::UnorderedElementsAre(kTestAndroidRealmBeta2, |
+ kTestAndroidRealmBeta3)); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedAndroidRealmsYieldsOnlyAndroidApps) { |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1), |
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()); |
+ // This verifies that |kTestWebRealmAlpha2| is not returned. |
+ EXPECT_THAT(GetAffiliatedAndroidRealms( |
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)), |
+ testing::UnorderedElementsAre(kTestAndroidRealmAlpha3)); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPBasicAuthForms) { |
+ PasswordStore::FormDigest http_auth_observed_form( |
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)); |
+ http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_BASIC; |
+ EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form), |
+ testing::IsEmpty()); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPDigestAuthForms) { |
+ PasswordStore::FormDigest http_auth_observed_form( |
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)); |
+ http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_DIGEST; |
+ EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form), |
+ testing::IsEmpty()); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedAndroidRealmsYieldsEmptyResultsForAndroidKeyedForms) { |
+ PasswordStore::FormDigest android_observed_form( |
+ GetTestAndroidCredentials(kTestAndroidRealmBeta2)); |
+ EXPECT_THAT(GetAffiliatedAndroidRealms(android_observed_form), |
+ testing::IsEmpty()); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedAndroidRealmsYieldsEmptyResultsWhenNoPrefetch) { |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure( |
+ FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1), |
+ StrategyOnCacheMiss::FAIL); |
+ EXPECT_THAT(GetAffiliatedAndroidRealms( |
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)), |
+ testing::IsEmpty()); |
+} |
+ |
+// GetAffiliatedWebRealms* tests verify that GetAffiliatedWebRealms() returns |
+// the realms of web sites affiliated with the given Android application, but |
+// only web sites, and only if an Android application is queried. |
+ |
+TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsResults) { |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3), |
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha()); |
+ PasswordStore::FormDigest android_form( |
+ GetTestAndroidCredentials(kTestAndroidRealmAlpha3)); |
+ EXPECT_THAT( |
+ GetAffiliatedWebRealms(android_form), |
+ testing::UnorderedElementsAre(kTestWebRealmAlpha1, kTestWebRealmAlpha2)); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsOnlyWebsites) { |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2), |
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassBeta()); |
+ PasswordStore::FormDigest android_form( |
+ GetTestAndroidCredentials(kTestAndroidRealmBeta2)); |
+ // This verifies that |kTestAndroidRealmBeta3| is not returned. |
+ EXPECT_THAT(GetAffiliatedWebRealms(android_form), |
+ testing::UnorderedElementsAre(kTestWebRealmBeta1)); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ GetAffiliatedWebRealmsYieldsEmptyResultsForWebKeyedForms) { |
+ EXPECT_THAT(GetAffiliatedWebRealms( |
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)), |
+ testing::IsEmpty()); |
+} |
+ |
+// Verifies that InjectAffiliatedWebRealms() injects the realms of web sites |
+// affiliated with the given Android application into password forms, if any. |
+TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) { |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms; |
+ |
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>( |
+ GetTestAndroidCredentials(kTestAndroidRealmAlpha3))); |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3), |
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()); |
+ |
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>( |
+ GetTestAndroidCredentials(kTestAndroidRealmBeta2))); |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2), |
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta()); |
+ |
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>( |
+ GetTestAndroidCredentials(kTestAndroidRealmGamma))); |
+ mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure( |
+ FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma), |
+ StrategyOnCacheMiss::FAIL); |
+ |
+ PasswordStore::FormDigest digest = |
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr); |
+ autofill::PasswordForm web_form; |
+ web_form.scheme = digest.scheme; |
+ web_form.signon_realm = digest.signon_realm; |
+ web_form.origin = digest.origin; |
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(web_form)); |
+ |
+ size_t expected_form_count = forms.size(); |
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results( |
+ InjectAffiliatedWebRealms(std::move(forms))); |
+ ASSERT_EQ(expected_form_count, results.size()); |
+ EXPECT_THAT(results[0]->affiliated_web_realm, |
+ testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2)); |
+ EXPECT_THAT(results[1]->affiliated_web_realm, |
+ testing::Eq(kTestWebRealmBeta1)); |
+ EXPECT_THAT(results[2]->affiliated_web_realm, testing::IsEmpty()); |
+ EXPECT_THAT(results[3]->affiliated_web_realm, testing::IsEmpty()); |
+} |
+ |
+// Note: IsValidWebCredential() is tested as part of GetAffiliatedAndroidRealms |
+// tests above. |
+TEST_F(AffiliatedMatchHelperTest, IsValidAndroidCredential) { |
+ EXPECT_FALSE(AffiliatedMatchHelper::IsValidAndroidCredential( |
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr))); |
+ PasswordStore::FormDigest android_credential( |
+ GetTestAndroidCredentials(kTestAndroidRealmBeta2)); |
+ EXPECT_TRUE( |
+ AffiliatedMatchHelper::IsValidAndroidCredential(android_credential)); |
+} |
+ |
+// Verifies that affiliations for Android applications with pre-existing |
+// credentials on start-up are prefetched. |
+TEST_F(AffiliatedMatchHelperTest, |
+ PrefetchAffiliationsForPreexistingAndroidCredentialsOnStartup) { |
+ AddAndroidAndNonAndroidTestLogins(); |
+ |
+ match_helper()->Initialize(); |
+ RunUntilIdle(); |
+ |
+ ExpectPrefetchForAndroidTestLogins(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+} |
+ |
+// Stores credentials for Android applications between Initialize() and |
+// DoDeferredInitialization(). Verifies that corresponding affiliation |
+// information gets prefetched. |
+TEST_F(AffiliatedMatchHelperTest, |
+ PrefetchAffiliationsForAndroidCredentialsAddedInInitializationDelay) { |
+ match_helper()->Initialize(); |
+ RunUntilIdle(); |
+ |
+ AddAndroidAndNonAndroidTestLogins(); |
+ |
+ ExpectPrefetchForAndroidTestLogins(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+} |
+ |
+// Stores credentials for Android applications after DoDeferredInitialization(). |
+// Verifies that corresponding affiliation information gets prefetched. |
+TEST_F(AffiliatedMatchHelperTest, |
+ PrefetchAffiliationsForAndroidCredentialsAddedAfterInitialization) { |
+ match_helper()->Initialize(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+ |
+ ExpectPrefetchForAndroidTestLogins(); |
+ AddAndroidAndNonAndroidTestLogins(); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, |
+ CancelPrefetchingAffiliationsForRemovedAndroidCredentials) { |
+ AddAndroidAndNonAndroidTestLogins(); |
+ match_helper()->Initialize(); |
+ ExpectPrefetchForAndroidTestLogins(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+ |
+ ExpectCancelPrefetchForAndroidTestLogins(); |
+ ExpectTrimCacheForAndroidTestLogins(); |
+ RemoveAndroidAndNonAndroidTestLogins(); |
+} |
+ |
+// Verify that whenever the primary key is updated for a credential (in which |
+// case both REMOVE and ADD change notifications are sent out), then Prefetch() |
+// is called in response to the addition before the call to TrimCacheForFacet() |
+// in response to the removal, so that cached data is not deleted and then |
+// immediately re-fetched. |
+TEST_F(AffiliatedMatchHelperTest, PrefetchBeforeTrimForPrimaryKeyUpdates) { |
+ AddAndroidAndNonAndroidTestLogins(); |
+ match_helper()->Initialize(); |
+ ExpectPrefetchForAndroidTestLogins(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+ |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIAlpha3); |
+ |
+ { |
+ testing::InSequence in_sequence; |
+ mock_affiliation_service()->ExpectCallToPrefetch( |
+ kTestAndroidFacetURIAlpha3); |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIAlpha3); |
+ } |
+ |
+ autofill::PasswordForm old_form( |
+ GetTestAndroidCredentials(kTestAndroidRealmAlpha3)); |
+ autofill::PasswordForm new_form(old_form); |
+ new_form.username_value = base::ASCIIToUTF16("NewUserName"); |
+ UpdateLoginWithPrimaryKey(new_form, old_form); |
+} |
+ |
+// Stores and removes four credentials for the same an Android application, and |
+// expects that Prefetch() and CancelPrefetch() will each be called four times. |
+TEST_F(AffiliatedMatchHelperTest, |
+ DuplicateCredentialsArePrefetchWithMultiplicity) { |
+ EXPECT_CALL(*mock_affiliation_service(), |
+ Prefetch(FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3), |
+ base::Time::Max())).Times(4); |
+ |
+ autofill::PasswordForm android_form( |
+ GetTestAndroidCredentials(kTestAndroidRealmAlpha3)); |
+ AddLogin(android_form); |
+ |
+ // Store two credentials before initialization. |
+ autofill::PasswordForm android_form2(android_form); |
+ android_form2.username_value = base::ASCIIToUTF16("JohnDoe2"); |
+ AddLogin(android_form2); |
+ |
+ match_helper()->Initialize(); |
+ RunUntilIdle(); |
+ |
+ // Store one credential between initialization and deferred initialization. |
+ autofill::PasswordForm android_form3(android_form); |
+ android_form3.username_value = base::ASCIIToUTF16("JohnDoe3"); |
+ AddLogin(android_form3); |
+ |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+ |
+ // Store one credential after deferred initialization. |
+ autofill::PasswordForm android_form4(android_form); |
+ android_form4.username_value = base::ASCIIToUTF16("JohnDoe4"); |
+ AddLogin(android_form4); |
+ |
+ for (size_t i = 0; i < 4; ++i) { |
+ mock_affiliation_service()->ExpectCallToCancelPrefetch( |
+ kTestAndroidFacetURIAlpha3); |
+ mock_affiliation_service()->ExpectCallToTrimCacheForFacet( |
+ kTestAndroidFacetURIAlpha3); |
+ } |
+ |
+ RemoveLogin(android_form); |
+ RemoveLogin(android_form2); |
+ RemoveLogin(android_form3); |
+ RemoveLogin(android_form4); |
+} |
+ |
+TEST_F(AffiliatedMatchHelperTest, DestroyBeforeDeferredInitialization) { |
+ match_helper()->Initialize(); |
+ RunUntilIdle(); |
+ DestroyMatchHelper(); |
+ ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization()); |
+} |
+ |
+} // namespace password_manager |