1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/run_loop.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
18 #include "base/test/task_environment.h"
19 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
20 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
21 #include "components/password_manager/core/browser/test_password_store.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace password_manager {
26 
27 namespace {
28 
29 using StrategyOnCacheMiss = AffiliationService::StrategyOnCacheMiss;
30 
31 class MockAffiliationService : public testing::StrictMock<AffiliationService> {
32  public:
MockAffiliationService()33   MockAffiliationService() : testing::StrictMock<AffiliationService>(nullptr) {
34     testing::DefaultValue<AffiliatedFacets>::Set(AffiliatedFacets());
35   }
36 
~MockAffiliationService()37   ~MockAffiliationService() override {}
38 
39   MOCK_METHOD2(OnGetAffiliationsAndBrandingCalled,
40                AffiliatedFacets(const FacetURI&, StrategyOnCacheMiss));
41   MOCK_METHOD2(Prefetch, void(const FacetURI&, const base::Time&));
42   MOCK_METHOD2(CancelPrefetch, void(const FacetURI&, const base::Time&));
43   MOCK_METHOD1(TrimCacheForFacetURI, void(const FacetURI&));
44 
GetAffiliationsAndBranding(const FacetURI & facet_uri,StrategyOnCacheMiss cache_miss_strategy,ResultCallback result_callback)45   void GetAffiliationsAndBranding(const FacetURI& facet_uri,
46                                   StrategyOnCacheMiss cache_miss_strategy,
47                                   ResultCallback result_callback) override {
48     AffiliatedFacets affiliation =
49         OnGetAffiliationsAndBrandingCalled(facet_uri, cache_miss_strategy);
50     std::move(result_callback).Run(affiliation, !affiliation.empty());
51   }
52 
ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(const FacetURI & expected_facet_uri,StrategyOnCacheMiss expected_cache_miss_strategy,const AffiliatedFacets & affiliations_to_return)53   void ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
54       const FacetURI& expected_facet_uri,
55       StrategyOnCacheMiss expected_cache_miss_strategy,
56       const AffiliatedFacets& affiliations_to_return) {
57     EXPECT_CALL(*this, OnGetAffiliationsAndBrandingCalled(
58                            expected_facet_uri, expected_cache_miss_strategy))
59         .WillOnce(testing::Return(affiliations_to_return));
60   }
61 
ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(const FacetURI & expected_facet_uri,StrategyOnCacheMiss expected_cache_miss_strategy)62   void ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
63       const FacetURI& expected_facet_uri,
64       StrategyOnCacheMiss expected_cache_miss_strategy) {
65     EXPECT_CALL(*this, OnGetAffiliationsAndBrandingCalled(
66                            expected_facet_uri, expected_cache_miss_strategy))
67         .WillOnce(testing::Return(AffiliatedFacets()));
68   }
69 
ExpectCallToPrefetch(const char * expected_facet_uri_spec)70   void ExpectCallToPrefetch(const char* expected_facet_uri_spec) {
71     EXPECT_CALL(*this,
72                 Prefetch(FacetURI::FromCanonicalSpec(expected_facet_uri_spec),
73                          base::Time::Max()))
74         .RetiresOnSaturation();
75   }
76 
ExpectCallToCancelPrefetch(const char * expected_facet_uri_spec)77   void ExpectCallToCancelPrefetch(const char* expected_facet_uri_spec) {
78     EXPECT_CALL(*this, CancelPrefetch(
79                            FacetURI::FromCanonicalSpec(expected_facet_uri_spec),
80                            base::Time::Max()))
81         .RetiresOnSaturation();
82   }
83 
ExpectCallToTrimCacheForFacetURI(const char * expected_facet_uri_spec)84   void ExpectCallToTrimCacheForFacetURI(const char* expected_facet_uri_spec) {
85     EXPECT_CALL(*this, TrimCacheForFacetURI(FacetURI::FromCanonicalSpec(
86                            expected_facet_uri_spec)))
87         .RetiresOnSaturation();
88   }
89 
90  private:
91   DISALLOW_ASSIGN(MockAffiliationService);
92 };
93 
94 const char kTestWebFacetURIAlpha1[] = "https://one.alpha.example.com";
95 const char kTestWebFacetURIAlpha2[] = "https://two.alpha.example.com";
96 const char kTestAndroidFacetURIAlpha3[] =
97     "android://hash@com.example.alpha.android";
98 const char kTestAndroidFacetNameAlpha3[] = "Facet Name Alpha 3";
99 const char kTestAndroidFacetIconURLAlpha3[] = "https://example.com/alpha_3.png";
100 const char kTestWebRealmAlpha1[] = "https://one.alpha.example.com/";
101 const char kTestWebRealmAlpha2[] = "https://two.alpha.example.com/";
102 const char kTestAndroidRealmAlpha3[] =
103     "android://hash@com.example.alpha.android/";
104 
105 const char kTestWebFacetURIBeta1[] = "https://one.beta.example.com";
106 const char kTestAndroidFacetURIBeta2[] =
107     "android://hash@com.example.beta.android";
108 const char kTestAndroidFacetNameBeta2[] = "Facet Name Beta 2";
109 const char kTestAndroidFacetIconURLBeta2[] = "https://example.com/beta_2.png";
110 const char kTestAndroidFacetURIBeta3[] =
111     "android://hash@com.yetanother.beta.android";
112 const char kTestAndroidFacetNameBeta3[] = "Facet Name Beta 3";
113 const char kTestAndroidFacetIconURLBeta3[] = "https://example.com/beta_3.png";
114 const char kTestWebRealmBeta1[] = "https://one.beta.example.com/";
115 const char kTestAndroidRealmBeta2[] =
116     "android://hash@com.example.beta.android/";
117 const char kTestAndroidRealmBeta3[] =
118     "android://hash@com.yetanother.beta.android/";
119 
120 const char kTestAndroidFacetURIGamma[] =
121     "android://hash@com.example.gamma.android";
122 const char kTestAndroidRealmGamma[] =
123     "android://hash@com.example.gamma.android";
124 
125 const char kTestUsername[] = "JohnDoe";
126 const char kTestPassword[] = "secret";
127 
GetTestEquivalenceClassAlpha()128 AffiliatedFacets GetTestEquivalenceClassAlpha() {
129   return {
130       {FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1)},
131       {FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha2)},
132       {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
133        FacetBrandingInfo{kTestAndroidFacetNameAlpha3,
134                          GURL(kTestAndroidFacetIconURLAlpha3)}},
135   };
136 }
137 
GetTestEquivalenceClassBeta()138 AffiliatedFacets GetTestEquivalenceClassBeta() {
139   return {
140       {FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1)},
141       {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
142        FacetBrandingInfo{kTestAndroidFacetNameBeta2,
143                          GURL(kTestAndroidFacetIconURLBeta2)}},
144       {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
145        FacetBrandingInfo{kTestAndroidFacetNameBeta3,
146                          GURL(kTestAndroidFacetIconURLBeta3)}},
147   };
148 }
149 
GetTestAndroidCredentials(const char * signon_realm)150 autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
151   autofill::PasswordForm form;
152   form.scheme = autofill::PasswordForm::Scheme::kHtml;
153   form.signon_realm = signon_realm;
154   form.username_value = base::ASCIIToUTF16(kTestUsername);
155   form.password_value = base::ASCIIToUTF16(kTestPassword);
156   return form;
157 }
158 
GetTestBlacklistedAndroidCredentials(const char * signon_realm)159 autofill::PasswordForm GetTestBlacklistedAndroidCredentials(
160     const char* signon_realm) {
161   autofill::PasswordForm form = GetTestAndroidCredentials(signon_realm);
162   form.blacklisted_by_user = true;
163   return form;
164 }
165 
GetTestObservedWebForm(const char * signon_realm,const char * origin)166 PasswordStore::FormDigest GetTestObservedWebForm(const char* signon_realm,
167                                                  const char* origin) {
168   return {autofill::PasswordForm::Scheme::kHtml, signon_realm,
169           origin ? GURL(origin) : GURL()};
170 }
171 
172 }  // namespace
173 
174 class AffiliatedMatchHelperTest : public testing::Test {
175  public:
AffiliatedMatchHelperTest()176   AffiliatedMatchHelperTest()
177       : expecting_result_callback_(false), mock_affiliation_service_(nullptr) {}
~AffiliatedMatchHelperTest()178   ~AffiliatedMatchHelperTest() override {}
179 
180  protected:
RunDeferredInitialization()181   void RunDeferredInitialization() {
182     mock_time_task_runner_->RunUntilIdle();
183     ASSERT_EQ(AffiliatedMatchHelper::kInitializationDelayOnStartup,
184               mock_time_task_runner_->NextPendingTaskDelay());
185     mock_time_task_runner_->FastForwardBy(
186         AffiliatedMatchHelper::kInitializationDelayOnStartup);
187   }
188 
ExpectNoDeferredTasks()189   void ExpectNoDeferredTasks() {
190     mock_time_task_runner_->RunUntilIdle();
191     ASSERT_FALSE(mock_time_task_runner_->HasPendingTask());
192   }
193 
RunUntilIdle()194   void RunUntilIdle() {
195     // TODO(gab): Add support for base::RunLoop().RunUntilIdle() in scope of
196     // ScopedMockTimeMessageLoopTaskRunner and use it instead of this helper
197     // method.
198     mock_time_task_runner_->RunUntilIdle();
199   }
200 
AddLogin(const autofill::PasswordForm & form)201   void AddLogin(const autofill::PasswordForm& form) {
202     password_store_->AddLogin(form);
203     RunUntilIdle();
204   }
205 
UpdateLoginWithPrimaryKey(const autofill::PasswordForm & new_form,const autofill::PasswordForm & old_primary_key)206   void UpdateLoginWithPrimaryKey(
207       const autofill::PasswordForm& new_form,
208       const autofill::PasswordForm& old_primary_key) {
209     password_store_->UpdateLoginWithPrimaryKey(new_form, old_primary_key);
210     RunUntilIdle();
211   }
212 
RemoveLogin(const autofill::PasswordForm & form)213   void RemoveLogin(const autofill::PasswordForm& form) {
214     password_store_->RemoveLogin(form);
215     RunUntilIdle();
216   }
217 
AddAndroidAndNonAndroidTestLogins()218   void AddAndroidAndNonAndroidTestLogins() {
219     AddLogin(GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
220     AddLogin(GetTestAndroidCredentials(kTestAndroidRealmBeta2));
221     AddLogin(GetTestBlacklistedAndroidCredentials(kTestAndroidRealmBeta3));
222     AddLogin(GetTestAndroidCredentials(kTestAndroidRealmGamma));
223 
224     AddLogin(GetTestAndroidCredentials(kTestWebRealmAlpha1));
225     AddLogin(GetTestAndroidCredentials(kTestWebRealmAlpha2));
226   }
227 
RemoveAndroidAndNonAndroidTestLogins()228   void RemoveAndroidAndNonAndroidTestLogins() {
229     RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
230     RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmBeta2));
231     RemoveLogin(GetTestBlacklistedAndroidCredentials(kTestAndroidRealmBeta3));
232     RemoveLogin(GetTestAndroidCredentials(kTestAndroidRealmGamma));
233 
234     RemoveLogin(GetTestAndroidCredentials(kTestWebRealmAlpha1));
235     RemoveLogin(GetTestAndroidCredentials(kTestWebRealmAlpha2));
236   }
237 
ExpectPrefetchForAndroidTestLogins()238   void ExpectPrefetchForAndroidTestLogins() {
239     mock_affiliation_service()->ExpectCallToPrefetch(
240         kTestAndroidFacetURIAlpha3);
241     mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIBeta2);
242     mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIBeta3);
243     mock_affiliation_service()->ExpectCallToPrefetch(kTestAndroidFacetURIGamma);
244   }
245 
ExpectCancelPrefetchForAndroidTestLogins()246   void ExpectCancelPrefetchForAndroidTestLogins() {
247     mock_affiliation_service()->ExpectCallToCancelPrefetch(
248         kTestAndroidFacetURIAlpha3);
249     mock_affiliation_service()->ExpectCallToCancelPrefetch(
250         kTestAndroidFacetURIBeta2);
251     mock_affiliation_service()->ExpectCallToCancelPrefetch(
252         kTestAndroidFacetURIBeta3);
253     mock_affiliation_service()->ExpectCallToCancelPrefetch(
254         kTestAndroidFacetURIGamma);
255   }
256 
ExpectTrimCacheForAndroidTestLogins()257   void ExpectTrimCacheForAndroidTestLogins() {
258     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
259         kTestAndroidFacetURIAlpha3);
260     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
261         kTestAndroidFacetURIBeta2);
262     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
263         kTestAndroidFacetURIBeta3);
264     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
265         kTestAndroidFacetURIGamma);
266   }
267 
GetAffiliatedAndroidRealms(const PasswordStore::FormDigest & observed_form)268   std::vector<std::string> GetAffiliatedAndroidRealms(
269       const PasswordStore::FormDigest& observed_form) {
270     expecting_result_callback_ = true;
271     match_helper()->GetAffiliatedAndroidRealms(
272         observed_form,
273         base::BindOnce(&AffiliatedMatchHelperTest::OnAffiliatedRealmsCallback,
274                        base::Unretained(this)));
275     RunUntilIdle();
276     EXPECT_FALSE(expecting_result_callback_);
277     return last_result_realms_;
278   }
279 
GetAffiliatedWebRealms(const PasswordStore::FormDigest & android_form)280   std::vector<std::string> GetAffiliatedWebRealms(
281       const PasswordStore::FormDigest& android_form) {
282     expecting_result_callback_ = true;
283     match_helper()->GetAffiliatedWebRealms(
284         android_form,
285         base::BindOnce(&AffiliatedMatchHelperTest::OnAffiliatedRealmsCallback,
286                        base::Unretained(this)));
287     RunUntilIdle();
288     EXPECT_FALSE(expecting_result_callback_);
289     return last_result_realms_;
290   }
291 
292   std::vector<std::unique_ptr<autofill::PasswordForm>>
InjectAffiliationAndBrandingInformation(std::vector<std::unique_ptr<autofill::PasswordForm>> forms)293   InjectAffiliationAndBrandingInformation(
294       std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
295     expecting_result_callback_ = true;
296     match_helper()->InjectAffiliationAndBrandingInformation(
297         std::move(forms),
298         base::BindOnce(&AffiliatedMatchHelperTest::OnFormsCallback,
299                        base::Unretained(this)));
300     RunUntilIdle();
301     EXPECT_FALSE(expecting_result_callback_);
302     return std::move(last_result_forms_);
303   }
304 
DestroyMatchHelper()305   void DestroyMatchHelper() { match_helper_.reset(); }
306 
password_store()307   TestPasswordStore* password_store() { return password_store_.get(); }
308 
mock_affiliation_service()309   MockAffiliationService* mock_affiliation_service() {
310     return mock_affiliation_service_;
311   }
312 
match_helper()313   AffiliatedMatchHelper* match_helper() { return match_helper_.get(); }
314 
315  private:
OnAffiliatedRealmsCallback(const std::vector<std::string> & affiliated_realms)316   void OnAffiliatedRealmsCallback(
317       const std::vector<std::string>& affiliated_realms) {
318     EXPECT_TRUE(expecting_result_callback_);
319     expecting_result_callback_ = false;
320     last_result_realms_ = affiliated_realms;
321   }
322 
OnFormsCallback(std::vector<std::unique_ptr<autofill::PasswordForm>> forms)323   void OnFormsCallback(
324       std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
325     EXPECT_TRUE(expecting_result_callback_);
326     expecting_result_callback_ = false;
327     last_result_forms_.swap(forms);
328   }
329 
330   // testing::Test:
SetUp()331   void SetUp() override {
332     std::unique_ptr<MockAffiliationService> service(
333         new MockAffiliationService());
334     mock_affiliation_service_ = service.get();
335 
336     password_store_ = new TestPasswordStore;
337     password_store_->Init(nullptr);
338 
339     match_helper_.reset(
340         new AffiliatedMatchHelper(password_store_.get(), std::move(service)));
341   }
342 
TearDown()343   void TearDown() override {
344     match_helper_.reset();
345     password_store_->ShutdownOnUIThread();
346     password_store_ = nullptr;
347     // Clean up on the background thread.
348     RunUntilIdle();
349   }
350 
351   base::test::SingleThreadTaskEnvironment task_environment_;
352   base::ScopedMockTimeMessageLoopTaskRunner mock_time_task_runner_;
353 
354   std::vector<std::string> last_result_realms_;
355   std::vector<std::unique_ptr<autofill::PasswordForm>> last_result_forms_;
356   bool expecting_result_callback_;
357 
358   scoped_refptr<TestPasswordStore> password_store_;
359   std::unique_ptr<AffiliatedMatchHelper> match_helper_;
360 
361   // Owned by |match_helper_|.
362   MockAffiliationService* mock_affiliation_service_;
363 
364   DISALLOW_COPY_AND_ASSIGN(AffiliatedMatchHelperTest);
365 };
366 
367 // GetAffiliatedAndroidRealm* tests verify that GetAffiliatedAndroidRealms()
368 // returns the realms of affiliated Android applications, but only Android
369 // applications, and only if the observed form is a secure HTML login form.
370 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsResults)371 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedAndroidRealmsYieldsResults) {
372   mock_affiliation_service()
373       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
374           FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1),
375           StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
376   EXPECT_THAT(GetAffiliatedAndroidRealms(
377                   GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)),
378               testing::UnorderedElementsAre(kTestAndroidRealmBeta2,
379                                             kTestAndroidRealmBeta3));
380 }
381 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsOnlyAndroidApps)382 TEST_F(AffiliatedMatchHelperTest,
383        GetAffiliatedAndroidRealmsYieldsOnlyAndroidApps) {
384   mock_affiliation_service()
385       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
386           FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
387           StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
388   // This verifies that |kTestWebRealmAlpha2| is not returned.
389   EXPECT_THAT(GetAffiliatedAndroidRealms(
390                   GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
391               testing::UnorderedElementsAre(kTestAndroidRealmAlpha3));
392 }
393 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPBasicAuthForms)394 TEST_F(AffiliatedMatchHelperTest,
395        GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPBasicAuthForms) {
396   PasswordStore::FormDigest http_auth_observed_form(
397       GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
398   http_auth_observed_form.scheme = autofill::PasswordForm::Scheme::kBasic;
399   EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
400               testing::IsEmpty());
401 }
402 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPDigestAuthForms)403 TEST_F(AffiliatedMatchHelperTest,
404        GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPDigestAuthForms) {
405   PasswordStore::FormDigest http_auth_observed_form(
406       GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
407   http_auth_observed_form.scheme = autofill::PasswordForm::Scheme::kDigest;
408   EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
409               testing::IsEmpty());
410 }
411 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsEmptyResultsForAndroidKeyedForms)412 TEST_F(AffiliatedMatchHelperTest,
413        GetAffiliatedAndroidRealmsYieldsEmptyResultsForAndroidKeyedForms) {
414   PasswordStore::FormDigest android_observed_form(
415       GetTestAndroidCredentials(kTestAndroidRealmBeta2));
416   EXPECT_THAT(GetAffiliatedAndroidRealms(android_observed_form),
417               testing::IsEmpty());
418 }
419 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedAndroidRealmsYieldsEmptyResultsWhenNoPrefetch)420 TEST_F(AffiliatedMatchHelperTest,
421        GetAffiliatedAndroidRealmsYieldsEmptyResultsWhenNoPrefetch) {
422   mock_affiliation_service()
423       ->ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
424           FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
425           StrategyOnCacheMiss::FAIL);
426   EXPECT_THAT(GetAffiliatedAndroidRealms(
427                   GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
428               testing::IsEmpty());
429 }
430 
431 // GetAffiliatedWebRealms* tests verify that GetAffiliatedWebRealms() returns
432 // the realms of web sites affiliated with the given Android application, but
433 // only web sites, and only if an Android application is queried.
434 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedWebRealmsYieldsResults)435 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsResults) {
436   mock_affiliation_service()
437       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
438           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
439           StrategyOnCacheMiss::FETCH_OVER_NETWORK,
440           GetTestEquivalenceClassAlpha());
441   PasswordStore::FormDigest android_form(
442       GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
443   EXPECT_THAT(
444       GetAffiliatedWebRealms(android_form),
445       testing::UnorderedElementsAre(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
446 }
447 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedWebRealmsYieldsOnlyWebsites)448 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsOnlyWebsites) {
449   mock_affiliation_service()
450       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
451           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
452           StrategyOnCacheMiss::FETCH_OVER_NETWORK,
453           GetTestEquivalenceClassBeta());
454   PasswordStore::FormDigest android_form(
455       GetTestAndroidCredentials(kTestAndroidRealmBeta2));
456   // This verifies that |kTestAndroidRealmBeta3| is not returned.
457   EXPECT_THAT(GetAffiliatedWebRealms(android_form),
458               testing::UnorderedElementsAre(kTestWebRealmBeta1));
459 }
460 
TEST_F(AffiliatedMatchHelperTest,GetAffiliatedWebRealmsYieldsEmptyResultsForWebKeyedForms)461 TEST_F(AffiliatedMatchHelperTest,
462        GetAffiliatedWebRealmsYieldsEmptyResultsForWebKeyedForms) {
463   EXPECT_THAT(GetAffiliatedWebRealms(
464                   GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)),
465               testing::IsEmpty());
466 }
467 
468 // Verifies that InjectAffiliationAndBrandingInformation() injects the realms of
469 // web sites affiliated with the given Android application into the password
470 // forms, as well as branding information corresponding to the application, if
471 // any.
TEST_F(AffiliatedMatchHelperTest,InjectAffiliationAndBrandingInformation)472 TEST_F(AffiliatedMatchHelperTest, InjectAffiliationAndBrandingInformation) {
473   std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
474 
475   forms.push_back(std::make_unique<autofill::PasswordForm>(
476       GetTestAndroidCredentials(kTestAndroidRealmAlpha3)));
477   mock_affiliation_service()
478       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
479           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
480           StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
481 
482   forms.push_back(std::make_unique<autofill::PasswordForm>(
483       GetTestAndroidCredentials(kTestAndroidRealmBeta2)));
484   mock_affiliation_service()
485       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
486           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
487           StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
488 
489   forms.push_back(std::make_unique<autofill::PasswordForm>(
490       GetTestAndroidCredentials(kTestAndroidRealmBeta3)));
491   mock_affiliation_service()
492       ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
493           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
494           StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
495 
496   forms.push_back(std::make_unique<autofill::PasswordForm>(
497       GetTestAndroidCredentials(kTestAndroidRealmGamma)));
498   mock_affiliation_service()
499       ->ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
500           FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
501           StrategyOnCacheMiss::FAIL);
502 
503   PasswordStore::FormDigest digest =
504       GetTestObservedWebForm(kTestWebRealmBeta1, nullptr);
505   autofill::PasswordForm web_form;
506   web_form.scheme = digest.scheme;
507   web_form.signon_realm = digest.signon_realm;
508   web_form.origin = digest.origin;
509   forms.push_back(std::make_unique<autofill::PasswordForm>(web_form));
510 
511   size_t expected_form_count = forms.size();
512   std::vector<std::unique_ptr<autofill::PasswordForm>> results(
513       InjectAffiliationAndBrandingInformation(std::move(forms)));
514   ASSERT_EQ(expected_form_count, results.size());
515   EXPECT_THAT(results[0]->affiliated_web_realm,
516               testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
517   EXPECT_EQ(kTestAndroidFacetNameAlpha3, results[0]->app_display_name);
518   EXPECT_EQ(kTestAndroidFacetIconURLAlpha3,
519             results[0]->app_icon_url.possibly_invalid_spec());
520   EXPECT_THAT(results[1]->affiliated_web_realm,
521               testing::Eq(kTestWebRealmBeta1));
522   EXPECT_EQ(kTestAndroidFacetNameBeta2, results[1]->app_display_name);
523   EXPECT_EQ(kTestAndroidFacetIconURLBeta2,
524             results[1]->app_icon_url.possibly_invalid_spec());
525   EXPECT_THAT(results[2]->affiliated_web_realm,
526               testing::Eq(kTestWebRealmBeta1));
527   EXPECT_EQ(kTestAndroidFacetNameBeta3, results[2]->app_display_name);
528   EXPECT_EQ(kTestAndroidFacetIconURLBeta3,
529             results[2]->app_icon_url.possibly_invalid_spec());
530   EXPECT_THAT(results[3]->affiliated_web_realm, testing::IsEmpty());
531   EXPECT_THAT(results[4]->affiliated_web_realm, testing::IsEmpty());
532 }
533 
534 // Note: IsValidWebCredential() is tested as part of GetAffiliatedAndroidRealms
535 // tests above.
TEST_F(AffiliatedMatchHelperTest,IsValidAndroidCredential)536 TEST_F(AffiliatedMatchHelperTest, IsValidAndroidCredential) {
537   EXPECT_FALSE(AffiliatedMatchHelper::IsValidAndroidCredential(
538       GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)));
539   PasswordStore::FormDigest android_credential(
540       GetTestAndroidCredentials(kTestAndroidRealmBeta2));
541   EXPECT_TRUE(
542       AffiliatedMatchHelper::IsValidAndroidCredential(android_credential));
543 }
544 
545 // Verifies that affiliations for Android applications with pre-existing
546 // credentials on start-up are prefetched.
TEST_F(AffiliatedMatchHelperTest,PrefetchAffiliationsAndBrandingForPreexistingAndroidCredentialsOnStartup)547 TEST_F(
548     AffiliatedMatchHelperTest,
549     PrefetchAffiliationsAndBrandingForPreexistingAndroidCredentialsOnStartup) {
550   AddAndroidAndNonAndroidTestLogins();
551 
552   match_helper()->Initialize();
553   RunUntilIdle();
554 
555   ExpectPrefetchForAndroidTestLogins();
556   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
557 }
558 
559 // Stores credentials for Android applications between Initialize() and
560 // DoDeferredInitialization(). Verifies that corresponding affiliation
561 // information gets prefetched.
TEST_F(AffiliatedMatchHelperTest,PrefetchAffiliationsForAndroidCredentialsAddedInInitializationDelay)562 TEST_F(AffiliatedMatchHelperTest,
563        PrefetchAffiliationsForAndroidCredentialsAddedInInitializationDelay) {
564   match_helper()->Initialize();
565   RunUntilIdle();
566 
567   AddAndroidAndNonAndroidTestLogins();
568 
569   ExpectPrefetchForAndroidTestLogins();
570   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
571 }
572 
573 // Stores credentials for Android applications after DoDeferredInitialization().
574 // Verifies that corresponding affiliation information gets prefetched.
TEST_F(AffiliatedMatchHelperTest,PrefetchAffiliationsForAndroidCredentialsAddedAfterInitialization)575 TEST_F(AffiliatedMatchHelperTest,
576        PrefetchAffiliationsForAndroidCredentialsAddedAfterInitialization) {
577   match_helper()->Initialize();
578   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
579 
580   ExpectPrefetchForAndroidTestLogins();
581   AddAndroidAndNonAndroidTestLogins();
582 }
583 
TEST_F(AffiliatedMatchHelperTest,CancelPrefetchingAffiliationsAndBrandingForRemovedAndroidCredentials)584 TEST_F(AffiliatedMatchHelperTest,
585        CancelPrefetchingAffiliationsAndBrandingForRemovedAndroidCredentials) {
586   AddAndroidAndNonAndroidTestLogins();
587   match_helper()->Initialize();
588   ExpectPrefetchForAndroidTestLogins();
589   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
590 
591   ExpectCancelPrefetchForAndroidTestLogins();
592   ExpectTrimCacheForAndroidTestLogins();
593   RemoveAndroidAndNonAndroidTestLogins();
594 }
595 
596 // Verify that whenever the primary key is updated for a credential (in which
597 // case both REMOVE and ADD change notifications are sent out), then Prefetch()
598 // is called in response to the addition before the call to
599 // TrimCacheForFacetURI() in response to the removal, so that cached data is not
600 // deleted and then immediately re-fetched.
TEST_F(AffiliatedMatchHelperTest,PrefetchBeforeTrimForPrimaryKeyUpdates)601 TEST_F(AffiliatedMatchHelperTest, PrefetchBeforeTrimForPrimaryKeyUpdates) {
602   AddAndroidAndNonAndroidTestLogins();
603   match_helper()->Initialize();
604   ExpectPrefetchForAndroidTestLogins();
605   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
606 
607   mock_affiliation_service()->ExpectCallToCancelPrefetch(
608       kTestAndroidFacetURIAlpha3);
609 
610   {
611     testing::InSequence in_sequence;
612     mock_affiliation_service()->ExpectCallToPrefetch(
613         kTestAndroidFacetURIAlpha3);
614     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
615         kTestAndroidFacetURIAlpha3);
616   }
617 
618   autofill::PasswordForm old_form(
619       GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
620   autofill::PasswordForm new_form(old_form);
621   new_form.username_value = base::ASCIIToUTF16("NewUserName");
622   UpdateLoginWithPrimaryKey(new_form, old_form);
623 }
624 
625 // Stores and removes four credentials for the same an Android application, and
626 // expects that Prefetch() and CancelPrefetch() will each be called four times.
TEST_F(AffiliatedMatchHelperTest,DuplicateCredentialsArePrefetchWithMultiplicity)627 TEST_F(AffiliatedMatchHelperTest,
628        DuplicateCredentialsArePrefetchWithMultiplicity) {
629   EXPECT_CALL(*mock_affiliation_service(),
630               Prefetch(FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
631                        base::Time::Max()))
632       .Times(4);
633 
634   autofill::PasswordForm android_form(
635       GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
636   AddLogin(android_form);
637 
638   // Store two credentials before initialization.
639   autofill::PasswordForm android_form2(android_form);
640   android_form2.username_value = base::ASCIIToUTF16("JohnDoe2");
641   AddLogin(android_form2);
642 
643   match_helper()->Initialize();
644   RunUntilIdle();
645 
646   // Store one credential between initialization and deferred initialization.
647   autofill::PasswordForm android_form3(android_form);
648   android_form3.username_value = base::ASCIIToUTF16("JohnDoe3");
649   AddLogin(android_form3);
650 
651   ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
652 
653   // Store one credential after deferred initialization.
654   autofill::PasswordForm android_form4(android_form);
655   android_form4.username_value = base::ASCIIToUTF16("JohnDoe4");
656   AddLogin(android_form4);
657 
658   for (size_t i = 0; i < 4; ++i) {
659     mock_affiliation_service()->ExpectCallToCancelPrefetch(
660         kTestAndroidFacetURIAlpha3);
661     mock_affiliation_service()->ExpectCallToTrimCacheForFacetURI(
662         kTestAndroidFacetURIAlpha3);
663   }
664 
665   RemoveLogin(android_form);
666   RemoveLogin(android_form2);
667   RemoveLogin(android_form3);
668   RemoveLogin(android_form4);
669 }
670 
TEST_F(AffiliatedMatchHelperTest,DestroyBeforeDeferredInitialization)671 TEST_F(AffiliatedMatchHelperTest, DestroyBeforeDeferredInitialization) {
672   match_helper()->Initialize();
673   RunUntilIdle();
674   DestroyMatchHelper();
675   ASSERT_NO_FATAL_FAILURE(ExpectNoDeferredTasks());
676 }
677 
678 }  // namespace password_manager
679