Fix emulator build error
[platform/framework/web/chromium-efl.git] / components / permissions / permission_uma_util_unittest.cc
1 // Copyright 2016 The Chromium Authors
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/permissions/permission_uma_util.h"
6
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/strings/strcat.h"
9 #include "base/test/metrics/histogram_tester.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "base/test/simple_test_clock.h"
12 #include "base/time/clock.h"
13 #include "base/time/time.h"
14 #include "base/values.h"
15 #include "components/content_settings/core/browser/content_settings_uma_util.h"
16 #include "components/content_settings/core/browser/host_content_settings_map.h"
17 #include "components/content_settings/core/common/content_settings_pattern.h"
18 #include "components/content_settings/core/common/content_settings_types.h"
19 #include "components/content_settings/core/common/features.h"
20 #include "components/permissions/constants.h"
21 #include "components/permissions/permission_request_manager.h"
22 #include "components/permissions/permission_util.h"
23 #include "components/permissions/test/test_permissions_client.h"
24 #include "components/ukm/content/source_url_recorder.h"
25 #include "components/ukm/test_ukm_recorder.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/test/browser_task_environment.h"
29 #include "content/public/test/navigation_simulator.h"
30 #include "content/public/test/test_browser_context.h"
31 #include "content/public/test/test_renderer_host.h"
32 #include "content/test/test_render_frame_host.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
35
36 namespace permissions {
37
38 namespace {
39
40 constexpr const char* kTopLevelUrl = "https://google.com";
41 constexpr const char* kSameOriginFrameUrl = "https://google.com/a/same.html";
42 constexpr const char* kCrossOriginFrameUrl = "https://embedded.google.com";
43 constexpr const char* kCrossOriginFrameUrl2 = "https://embedded2.google.com";
44
45 constexpr const char* kGeolocationUsageHistogramName =
46     "Permissions.Experimental.Usage.Geolocation.IsCrossOriginFrame";
47 constexpr const char* kGeolocationPermissionsPolicyUsageHistogramName =
48     "Permissions.Experimental.Usage.Geolocation.CrossOriginFrame."
49     "TopLevelHeaderPolicy";
50 constexpr const char* kGeolocationPermissionsPolicyActionHistogramName =
51     "Permissions.Action.Geolocation.CrossOriginFrame."
52     "TopLevelHeaderPolicy";
53
54 blink::ParsedPermissionsPolicy CreatePermissionsPolicy(
55     blink::mojom::PermissionsPolicyFeature feature,
56     const std::vector<std::string>& origins,
57     bool matches_all_origins = false) {
58   std::vector<blink::OriginWithPossibleWildcards> allow_origins;
59   for (const auto& origin : origins) {
60     allow_origins.emplace_back(*blink::OriginWithPossibleWildcards::FromOrigin(
61         url::Origin::Create(GURL(origin))));
62   }
63   return {{feature, allow_origins, /*self_if_matches=*/absl::nullopt,
64            matches_all_origins,
65            /*matches_opaque_src*/ false}};
66 }
67
68 PermissionRequestManager* SetupRequestManager(
69     content::WebContents* web_contents) {
70   PermissionRequestManager::CreateForWebContents(web_contents);
71   return PermissionRequestManager::FromWebContents(web_contents);
72 }
73
74 struct PermissionsDelegationTestConfig {
75   ContentSettingsType type;
76   PermissionAction action;
77   absl::optional<blink::mojom::PermissionsPolicyFeature> feature_overriden;
78
79   bool matches_all_origins;
80   std::vector<std::string> origins;
81
82   // Expected resulting permissions policy configuration.
83   absl::optional<PermissionHeaderPolicyForUMA> expected_configuration;
84 };
85
86 #if !BUILDFLAG(IS_ANDROID)
87 ContentSettingsForOneType GetRevokedUnusedPermissions(
88     HostContentSettingsMap* hcsm) {
89   return hcsm->GetSettingsForOneType(
90       ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS);
91 }
92 #endif
93
94 // Wrapper class so that we can pass a closure to the PermissionRequest
95 // ctor, to handle all dtor paths (avoid crash in dtor of WebContent)
96 class PermissionRequestWrapper {
97  public:
98   explicit PermissionRequestWrapper(permissions::RequestType type,
99                                     const char* url) {
100     const bool user_gesture = true;
101     auto decided = [](ContentSetting, bool, bool) {};
102     request_ = std::make_unique<permissions::PermissionRequest>(
103         GURL(url), type, user_gesture, base::BindRepeating(decided),
104         base::BindOnce(&PermissionRequestWrapper::DeleteThis,
105                        base::Unretained(this)));
106   }
107
108   PermissionRequestWrapper(const PermissionRequestWrapper&) = delete;
109   PermissionRequestWrapper& operator=(const PermissionRequestWrapper&) = delete;
110
111   permissions::PermissionRequest* request() { return request_.get(); }
112
113  private:
114   void DeleteThis() { delete this; }
115
116   std::unique_ptr<permissions::PermissionRequest> request_;
117 };
118
119 }  // namespace
120
121 class PermissionsDelegationUmaUtilTest
122     : public content::RenderViewHostTestHarness,
123       public testing::WithParamInterface<PermissionsDelegationTestConfig> {
124  protected:
125   void SetUp() override { RenderViewHostTestHarness::SetUp(); }
126
127   content::RenderFrameHost* GetMainFrameAndNavigate(const char* origin) {
128     content::RenderFrameHost* result = web_contents()->GetPrimaryMainFrame();
129     content::RenderFrameHostTester::For(result)
130         ->InitializeRenderFrameIfNeeded();
131     SimulateNavigation(&result, GURL(origin));
132     return result;
133   }
134
135   content::RenderFrameHost* AddChildFrameWithPermissionsPolicy(
136       content::RenderFrameHost* parent,
137       const char* origin,
138       blink::ParsedPermissionsPolicy policy) {
139     content::RenderFrameHost* result =
140         content::RenderFrameHostTester::For(parent)->AppendChildWithPolicy(
141             "", policy);
142     content::RenderFrameHostTester::For(result)
143         ->InitializeRenderFrameIfNeeded();
144     SimulateNavigation(&result, GURL(origin));
145     return result;
146   }
147
148   // The permissions policy is invariant and required the page to be
149   // refreshed
150   void RefreshAndSetPermissionsPolicy(content::RenderFrameHost** rfh,
151                                       blink::ParsedPermissionsPolicy policy) {
152     content::RenderFrameHost* current = *rfh;
153     auto navigation = content::NavigationSimulator::CreateRendererInitiated(
154         current->GetLastCommittedURL(), current);
155     navigation->SetPermissionsPolicyHeader(policy);
156     navigation->Commit();
157     *rfh = navigation->GetFinalRenderFrameHost();
158   }
159
160   // Simulates navigation and returns the final RenderFrameHost.
161   void SimulateNavigation(content::RenderFrameHost** rfh, const GURL& url) {
162     auto navigation_simulator =
163         content::NavigationSimulator::CreateRendererInitiated(url, *rfh);
164     navigation_simulator->Commit();
165     *rfh = navigation_simulator->GetFinalRenderFrameHost();
166   }
167
168  private:
169   TestPermissionsClient permissions_client_;
170 };
171
172 class PermissionUmaUtilTest : public testing::Test {
173  private:
174   content::BrowserTaskEnvironment task_environment_;
175   TestPermissionsClient permissions_client_;
176 };
177
178 TEST_F(PermissionUmaUtilTest, ScopedRevocationReporter) {
179   content::TestBrowserContext browser_context;
180
181   // TODO(tsergeant): Add more comprehensive tests of PermissionUmaUtil.
182   base::HistogramTester histograms;
183   HostContentSettingsMap* map =
184       PermissionsClient::Get()->GetSettingsMap(&browser_context);
185   GURL host("https://example.com");
186   ContentSettingsPattern host_pattern =
187       ContentSettingsPattern::FromURLNoWildcard(host);
188   ContentSettingsPattern host_containing_wildcards_pattern =
189       ContentSettingsPattern::FromString("https://[*.]example.com/");
190   ContentSettingsType type = ContentSettingsType::GEOLOCATION;
191   PermissionSourceUI source_ui = PermissionSourceUI::SITE_SETTINGS;
192
193   // Allow->Block triggers a revocation.
194   map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
195   {
196     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
197         &browser_context, host, host, type, source_ui);
198     map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_BLOCK);
199   }
200   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
201                                static_cast<int>(PermissionAction::REVOKED), 1);
202
203   // Block->Allow does not trigger a revocation.
204   {
205     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
206         &browser_context, host, host, type, source_ui);
207     map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
208   }
209   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
210                                static_cast<int>(PermissionAction::REVOKED), 1);
211
212   // Allow->Default triggers a revocation when default is 'ask'.
213   map->SetDefaultContentSetting(type, CONTENT_SETTING_ASK);
214   {
215     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
216         &browser_context, host, host, type, source_ui);
217     map->SetContentSettingDefaultScope(host, host, type,
218                                        CONTENT_SETTING_DEFAULT);
219   }
220   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
221                                static_cast<int>(PermissionAction::REVOKED), 2);
222
223   // Allow->Default does not trigger a revocation when default is 'allow'.
224   map->SetDefaultContentSetting(type, CONTENT_SETTING_ALLOW);
225   {
226     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
227         &browser_context, host, host, type, source_ui);
228     map->SetContentSettingDefaultScope(host, host, type,
229                                        CONTENT_SETTING_DEFAULT);
230   }
231   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
232                                static_cast<int>(PermissionAction::REVOKED), 2);
233
234   // Allow->Block with url pattern string triggers a revocation.
235   map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
236   {
237     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
238         &browser_context, host_pattern, host_pattern, type, source_ui);
239     map->SetContentSettingCustomScope(host_pattern,
240                                       ContentSettingsPattern::Wildcard(), type,
241                                       CONTENT_SETTING_BLOCK);
242   }
243   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
244                                static_cast<int>(PermissionAction::REVOKED), 3);
245
246   // Allow->Block with non url pattern string does not trigger a revocation.
247   map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
248   {
249     PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
250         &browser_context, host_containing_wildcards_pattern, host_pattern, type,
251         source_ui);
252     map->SetContentSettingCustomScope(host_containing_wildcards_pattern,
253                                       ContentSettingsPattern::Wildcard(), type,
254                                       CONTENT_SETTING_BLOCK);
255   }
256   histograms.ExpectBucketCount("Permissions.Action.Geolocation",
257                                static_cast<int>(PermissionAction::REVOKED), 3);
258 }
259
260 TEST_F(PermissionUmaUtilTest, CrowdDenyVersionTest) {
261   base::HistogramTester histograms;
262
263   const absl::optional<base::Version> empty_version;
264   PermissionUmaUtil::RecordCrowdDenyVersionAtAbuseCheckTime(empty_version);
265   histograms.ExpectBucketCount(
266       "Permissions.CrowdDeny.PreloadData.VersionAtAbuseCheckTime", 0, 1);
267
268   const absl::optional<base::Version> valid_version =
269       base::Version({2020, 10, 11, 1234});
270   PermissionUmaUtil::RecordCrowdDenyVersionAtAbuseCheckTime(valid_version);
271   histograms.ExpectBucketCount(
272       "Permissions.CrowdDeny.PreloadData.VersionAtAbuseCheckTime", 20201011, 1);
273
274   const absl::optional<base::Version> valid_old_version =
275       base::Version({2019, 10, 10, 1234});
276   PermissionUmaUtil::RecordCrowdDenyVersionAtAbuseCheckTime(valid_old_version);
277   histograms.ExpectBucketCount(
278       "Permissions.CrowdDeny.PreloadData.VersionAtAbuseCheckTime", 1, 1);
279
280   const absl::optional<base::Version> valid_future_version =
281       base::Version({2021, 1, 1, 1234});
282   PermissionUmaUtil::RecordCrowdDenyVersionAtAbuseCheckTime(
283       valid_future_version);
284   histograms.ExpectBucketCount(
285       "Permissions.CrowdDeny.PreloadData.VersionAtAbuseCheckTime", 20210101, 1);
286
287   const absl::optional<base::Version> invalid_version =
288       base::Version({2020, 10, 11});
289   PermissionUmaUtil::RecordCrowdDenyVersionAtAbuseCheckTime(valid_version);
290   histograms.ExpectBucketCount(
291       "Permissions.CrowdDeny.PreloadData.VersionAtAbuseCheckTime", 1, 1);
292 }
293
294 // Test that the appropriate UMA metrics have been recorded when the DSE is
295 // disabled.
296 TEST_F(PermissionUmaUtilTest, MetricsAreRecordedWhenAutoDSEPermissionReverted) {
297   const std::string kTransitionHistogramPrefix =
298       "Permissions.DSE.AutoPermissionRevertTransition.";
299
300   constexpr struct {
301     ContentSetting backed_up_setting;
302     ContentSetting effective_setting;
303     ContentSetting end_state_setting;
304     permissions::AutoDSEPermissionRevertTransition expected_transition;
305   } kTests[] = {
306       // Expected valid combinations.
307       {CONTENT_SETTING_ASK, CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
308        permissions::AutoDSEPermissionRevertTransition::NO_DECISION_ASK},
309       {CONTENT_SETTING_ALLOW, CONTENT_SETTING_ALLOW, CONTENT_SETTING_ALLOW,
310        permissions::AutoDSEPermissionRevertTransition::PRESERVE_ALLOW},
311       {CONTENT_SETTING_BLOCK, CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
312        permissions::AutoDSEPermissionRevertTransition::CONFLICT_ASK},
313       {CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK, CONTENT_SETTING_BLOCK,
314        permissions::AutoDSEPermissionRevertTransition::PRESERVE_BLOCK_ASK},
315       {CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK, CONTENT_SETTING_BLOCK,
316        permissions::AutoDSEPermissionRevertTransition::PRESERVE_BLOCK_ALLOW},
317       {CONTENT_SETTING_BLOCK, CONTENT_SETTING_BLOCK, CONTENT_SETTING_BLOCK,
318        permissions::AutoDSEPermissionRevertTransition::PRESERVE_BLOCK_BLOCK},
319   };
320
321   // We test every combination of test case for notifications and geolocation to
322   // basically test the entire possible transition space.
323   for (const auto& test : kTests) {
324     for (const auto type : {ContentSettingsType::NOTIFICATIONS,
325                             ContentSettingsType::GEOLOCATION}) {
326       const std::string type_string = type == ContentSettingsType::NOTIFICATIONS
327                                           ? "Notifications"
328                                           : "Geolocation";
329       base::HistogramTester histograms;
330       PermissionUmaUtil::RecordAutoDSEPermissionReverted(
331           type, test.backed_up_setting, test.effective_setting,
332           test.end_state_setting);
333
334       // Test that the expected samples are recorded in histograms.
335       histograms.ExpectBucketCount(kTransitionHistogramPrefix + type_string,
336                                    test.expected_transition, 1);
337       histograms.ExpectTotalCount(kTransitionHistogramPrefix + type_string, 1);
338     }
339   }
340 }
341
342 TEST_F(PermissionsDelegationUmaUtilTest, UsageAndPromptInTopLevelFrame) {
343   base::HistogramTester histograms;
344   auto* main_frame = GetMainFrameAndNavigate(kTopLevelUrl);
345   histograms.ExpectTotalCount(kGeolocationUsageHistogramName, 0);
346
347   auto* permission_request_manager = SetupRequestManager(web_contents());
348   PermissionRequestWrapper* request_owner =
349       new PermissionRequestWrapper(RequestType::kGeolocation, kTopLevelUrl);
350   permission_request_manager->AddRequest(main_frame, request_owner->request());
351   PermissionUmaUtil::RecordPermissionsUsageSourceAndPolicyConfiguration(
352       ContentSettingsType::GEOLOCATION, main_frame);
353   EXPECT_THAT(histograms.GetAllSamples(kGeolocationUsageHistogramName),
354               testing::ElementsAre(base::Bucket(0, 1)));
355   PermissionUmaUtil::PermissionPromptResolved(
356       {request_owner->request()}, web_contents(), PermissionAction::GRANTED,
357       /*time_to_decision*/ base::TimeDelta(),
358       PermissionPromptDisposition::NOT_APPLICABLE,
359       /* ui_reason*/ absl::nullopt,
360       /*predicted_grant_likelihood*/ absl::nullopt,
361       /*prediction_decision_held_back*/ absl::nullopt,
362       /*ignored_reason*/ absl::nullopt, /*did_show_prompt*/ false,
363       /*did_click_managed*/ false,
364       /*did_click_learn_more*/ false);
365   histograms.ExpectTotalCount(kGeolocationPermissionsPolicyActionHistogramName,
366                               0);
367 }
368
369 TEST_F(PermissionUmaUtilTest, PageInfoPermissionReallowedTest) {
370   base::HistogramTester histograms;
371
372   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
373       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/true,
374       /*show_infobar=*/true, /*page_reload=*/true);
375   histograms.ExpectBucketCount(
376       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
377       permissions::PermissionChangeInfo::kInfobarShownPageReloadPermissionUsed,
378       1);
379
380   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
381       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/false,
382       /*show_infobar=*/true, /*page_reload=*/true);
383   histograms.ExpectBucketCount(
384       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
385       permissions::PermissionChangeInfo::
386           kInfobarShownPageReloadPermissionNotUsed,
387       1);
388
389   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
390       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/true,
391       /*show_infobar=*/true, /*page_reload=*/false);
392   histograms.ExpectBucketCount(
393       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
394       permissions::PermissionChangeInfo::
395           kInfobarShownNoPageReloadPermissionUsed,
396       1);
397
398   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
399       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/false,
400       /*show_infobar=*/true, /*page_reload=*/false);
401   histograms.ExpectBucketCount(
402       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
403       permissions::PermissionChangeInfo::
404           kInfobarShownNoPageReloadPermissionNotUsed,
405       1);
406
407   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
408       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/true,
409       /*show_infobar=*/false, /*page_reload=*/true);
410   histograms.ExpectBucketCount(
411       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
412       permissions::PermissionChangeInfo::
413           kInfobarNotShownPageReloadPermissionUsed,
414       1);
415
416   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
417       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/false,
418       /*show_infobar=*/false, /*page_reload=*/true);
419   histograms.ExpectBucketCount(
420       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
421       permissions::PermissionChangeInfo::
422           kInfobarNotShownPageReloadPermissionNotUsed,
423       1);
424
425   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
426       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/true,
427       /*show_infobar=*/false, /*page_reload=*/false);
428   histograms.ExpectBucketCount(
429       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
430       permissions::PermissionChangeInfo::
431           kInfobarNotShownNoPageReloadPermissionUsed,
432       1);
433
434   PermissionUmaUtil::RecordPermissionRecoverySuccessRate(
435       ContentSettingsType::MEDIASTREAM_CAMERA, /*is_used=*/false,
436       /*show_infobar=*/false, /*page_reload=*/false);
437   histograms.ExpectBucketCount(
438       "Permissions.PageInfo.Changed.VideoCapture.Reallowed.Outcome",
439       permissions::PermissionChangeInfo::
440           kInfobarNotShownNoPageReloadPermissionNotUsed,
441       1);
442 }
443
444 #if !BUILDFLAG(IS_ANDROID)
445 TEST_F(PermissionUmaUtilTest, RecordPermissionRegrantForUnusedSites) {
446   const GURL origin = GURL("https://example1.com:443");
447   content::TestBrowserContext browser_context;
448   base::HistogramTester histograms;
449   ContentSettingsType content_type = ContentSettingsType::GEOLOCATION;
450   std::string permission_string =
451       PermissionUtil::GetPermissionString(content_type);
452   base::SimpleTestClock clock;
453   base::Time now(base::Time::Now());
454   clock.SetNow(now);
455   HostContentSettingsMap* hcsm =
456       PermissionsClient::Get()->GetSettingsMap(&browser_context);
457   hcsm->SetClockForTesting(&clock);
458
459   std::string prefix = "Settings.SafetyCheck.UnusedSitePermissionsRegrantDays";
460
461   // Record regrant before permission has been revoked.
462   PermissionUmaUtil::RecordPermissionRegrantForUnusedSites(
463       origin, content_type, PermissionSourceUI::PROMPT, &browser_context, now);
464   histograms.ExpectTotalCount(prefix + "Prompt." + permission_string, 0);
465   histograms.ExpectTotalCount(prefix + "Prompt.All", 0);
466
467   // Create a revoked permission.
468   auto dict = base::Value::Dict().Set(
469       permissions::kRevokedKey,
470       base::Value::List().Append(static_cast<int32_t>(content_type)));
471   // Set expiration to five days before the clean-up threshold to mimic that the
472   // permission was revoked five days ago.
473   base::Time past(now - base::Days(5));
474   content_settings::ContentSettingConstraints constraint(past);
475   constraint.set_lifetime(
476       content_settings::features::
477           kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold.Get());
478   hcsm->SetWebsiteSettingDefaultScope(
479       origin, origin, ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS,
480       base::Value(dict.Clone()), constraint);
481
482   // Regrant another permission through the prompt.
483   PermissionUmaUtil::RecordPermissionRegrantForUnusedSites(
484       origin, ContentSettingsType::NOTIFICATIONS, PermissionSourceUI::PROMPT,
485       &browser_context, now);
486   histograms.ExpectTotalCount(prefix + "Prompt." +
487                                   PermissionUtil::GetPermissionString(
488                                       ContentSettingsType::NOTIFICATIONS),
489                               0);
490   histograms.ExpectTotalCount(prefix + "Prompt.All", 0);
491
492   // Regrant the geolocation permission through the prompt.
493   PermissionUmaUtil::RecordPermissionRegrantForUnusedSites(
494       origin, content_type, PermissionSourceUI::PROMPT, &browser_context, now);
495   histograms.ExpectBucketCount(prefix + "Prompt." + permission_string, 5, 1);
496   histograms.ExpectBucketCount(prefix + "Prompt.All", 5, 1);
497
498   // Regrant the geolocation permission through site settings.
499   PermissionUmaUtil::RecordPermissionRegrantForUnusedSites(
500       origin, content_type, PermissionSourceUI::SITE_SETTINGS, &browser_context,
501       now);
502   histograms.ExpectBucketCount(prefix + "Settings." + permission_string, 5, 1);
503   histograms.ExpectBucketCount(prefix + "Settings.All", 5, 1);
504 }
505
506 TEST_F(PermissionUmaUtilTest, GetDaysSinceUnusedSitePermissionRevocation) {
507   base::test::ScopedFeatureList scoped_feature;
508   scoped_feature.InitAndEnableFeature(
509       content_settings::features::kSafetyCheckUnusedSitePermissions);
510
511   content::TestBrowserContext browser_context;
512   base::SimpleTestClock clock;
513   base::Time now(base::Time::Now());
514   clock.SetNow(now);
515   HostContentSettingsMap* hcsm =
516       PermissionsClient::Get()->GetSettingsMap(&browser_context);
517
518   const GURL url = GURL("https://example1.com:443");
519   const ContentSettingsType type = ContentSettingsType::GEOLOCATION;
520   content_settings::ContentSettingConstraints constraint(clock.Now());
521   constraint.set_track_last_visit_for_autoexpiration(true);
522
523   absl::optional<uint32_t> days_since_revocation;
524
525   // Permission has not yet been revoked, so shouldn't return a number of days
526   // since revocation.
527   days_since_revocation =
528       PermissionUmaUtil::GetDaysSinceUnusedSitePermissionRevocation(
529           url, ContentSettingsType::GEOLOCATION, now, hcsm);
530   ASSERT_FALSE(days_since_revocation.has_value());
531
532   hcsm->SetContentSettingDefaultScope(
533       url, url, type, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
534   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm).size(), 0u);
535
536   // Travel 70 days through time such that the granted permission would be
537   // revoked.
538   clock.Advance(base::Days(70));
539   // Revoke permission.
540   content_settings::ContentSettingConstraints expiration_constraint(
541       clock.Now());
542   expiration_constraint.set_lifetime(base::Days(30));
543   auto dict = base::Value::Dict().Set(
544       permissions::kRevokedKey, base::Value::List().Append(static_cast<int32_t>(
545                                     ContentSettingsType::GEOLOCATION)));
546   hcsm->SetWebsiteSettingCustomScope(
547       ContentSettingsPattern::FromURLNoWildcard(url),
548       ContentSettingsPattern::Wildcard(),
549       ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS,
550       base::Value(std::move(dict)), expiration_constraint);
551   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm).size(), 1u);
552
553   days_since_revocation =
554       PermissionUmaUtil::GetDaysSinceUnusedSitePermissionRevocation(
555           url, ContentSettingsType::GEOLOCATION, clock.Now(), hcsm);
556   ASSERT_TRUE(days_since_revocation.has_value());
557   EXPECT_EQ(days_since_revocation.value(), 0u);
558
559   // Forward the clock for five days, which would be the number of days since
560   // revocation.
561   clock.Advance(base::Days(5));
562
563   days_since_revocation =
564       PermissionUmaUtil::GetDaysSinceUnusedSitePermissionRevocation(
565           url, ContentSettingsType::GEOLOCATION, clock.Now(), hcsm);
566   ASSERT_TRUE(days_since_revocation.has_value());
567   EXPECT_EQ(days_since_revocation.value(), 5u);
568 }
569 #endif
570
571 TEST_F(PermissionsDelegationUmaUtilTest, SameOriginFrame) {
572   base::HistogramTester histograms;
573   auto* main_frame = GetMainFrameAndNavigate(kTopLevelUrl);
574   auto* child_frame = AddChildFrameWithPermissionsPolicy(
575       main_frame, kSameOriginFrameUrl,
576       CreatePermissionsPolicy(
577           blink::mojom::PermissionsPolicyFeature::kGeolocation,
578           {std::string(kTopLevelUrl), std::string(kSameOriginFrameUrl)},
579           /*matches_all_origins*/ true));
580   histograms.ExpectTotalCount(kGeolocationUsageHistogramName, 0);
581
582   auto* permission_request_manager = SetupRequestManager(web_contents());
583   PermissionRequestWrapper* request_owner = new PermissionRequestWrapper(
584       RequestType::kGeolocation, kSameOriginFrameUrl);
585   permission_request_manager->AddRequest(child_frame, request_owner->request());
586   PermissionUmaUtil::RecordPermissionsUsageSourceAndPolicyConfiguration(
587       ContentSettingsType::GEOLOCATION, child_frame);
588   EXPECT_THAT(histograms.GetAllSamples(kGeolocationUsageHistogramName),
589               testing::ElementsAre(base::Bucket(0, 1)));
590   histograms.ExpectTotalCount(kGeolocationPermissionsPolicyUsageHistogramName,
591                               0);
592   PermissionUmaUtil::PermissionPromptResolved(
593       {request_owner->request()}, web_contents(), PermissionAction::GRANTED,
594       /*time_to_decision*/ base::TimeDelta(),
595       PermissionPromptDisposition::NOT_APPLICABLE,
596       /* ui_reason*/ absl::nullopt,
597       /*predicted_grant_likelihood*/ absl::nullopt,
598       /*prediction_decision_held_back*/ absl::nullopt,
599       /*ignored_reason*/ absl::nullopt, /*did_show_prompt*/ false,
600       /*did_click_managed*/ false,
601       /*did_click_learn_more*/ false);
602   histograms.ExpectTotalCount(kGeolocationPermissionsPolicyActionHistogramName,
603                               0);
604 }
605
606 TEST_P(PermissionsDelegationUmaUtilTest, TopLevelFrame) {
607   auto type = GetParam().type;
608   std::string permission_string = PermissionUtil::GetPermissionString(type);
609   // The histogram values should match with the ones defined in
610   // |permission_uma_util.cc|
611   std::string kPermissionsPolicyHeaderHistogramName =
612       base::StrCat({"Permissions.Experimental.PrimaryMainNavigationFinished.",
613                     permission_string, ".TopLevelHeaderPolicy"});
614
615   base::HistogramTester histograms;
616   auto* main_frame = GetMainFrameAndNavigate(kTopLevelUrl);
617   auto feature = PermissionUtil::GetPermissionsPolicyFeature(type);
618   blink::ParsedPermissionsPolicy top_policy;
619   if (feature.has_value() &&
620       (GetParam().matches_all_origins || !GetParam().origins.empty())) {
621     top_policy = CreatePermissionsPolicy(
622         GetParam().feature_overriden.has_value()
623             ? GetParam().feature_overriden.value()
624             : feature.value(),
625         GetParam().origins, GetParam().matches_all_origins);
626   }
627
628   if (!top_policy.empty()) {
629     RefreshAndSetPermissionsPolicy(&main_frame, top_policy);
630   }
631
632   histograms.ExpectTotalCount(kPermissionsPolicyHeaderHistogramName, 0);
633
634   PermissionUmaUtil::RecordTopLevelPermissionsHeaderPolicyOnNavigation(
635       main_frame);
636   EXPECT_THAT(
637       histograms.GetAllSamples(kPermissionsPolicyHeaderHistogramName),
638       testing::ElementsAre(base::Bucket(
639           static_cast<int>(GetParam().expected_configuration.value()), 1)));
640 }
641
642 INSTANTIATE_TEST_SUITE_P(
643     TopLevelFrame,
644     PermissionsDelegationUmaUtilTest,
645     testing::Values(
646         PermissionsDelegationTestConfig{
647             ContentSettingsType::GEOLOCATION, PermissionAction::GRANTED,
648             /*feature_overriden*/ absl::nullopt,
649             /*matches_all_origins*/ true,
650             /*origins*/ {},
651             PermissionHeaderPolicyForUMA::FEATURE_ALLOWLIST_IS_WILDCARD},
652
653         PermissionsDelegationTestConfig{
654             ContentSettingsType::GEOLOCATION,
655             PermissionAction::GRANTED,
656             /*feature_overriden*/ absl::nullopt,
657             /*matches_all_origins*/ false,
658             {std::string(kTopLevelUrl)},
659             PermissionHeaderPolicyForUMA::
660                 FEATURE_ALLOWLIST_EXPLICITLY_MATCHES_ORIGIN},
661
662         PermissionsDelegationTestConfig{
663             ContentSettingsType::GEOLOCATION, PermissionAction::GRANTED,
664             /*feature_overriden*/ absl::nullopt,
665             /*matches_all_origins*/ false,
666             /*origins*/ {},
667             PermissionHeaderPolicyForUMA::HEADER_NOT_PRESENT_OR_INVALID},
668
669         PermissionsDelegationTestConfig{
670             ContentSettingsType::GEOLOCATION,
671             PermissionAction::GRANTED,
672             absl::make_optional<blink::mojom::PermissionsPolicyFeature>(
673                 blink::mojom::PermissionsPolicyFeature::kCamera),
674             /*matches_all_origins*/ false,
675             {std::string(kTopLevelUrl)},
676             PermissionHeaderPolicyForUMA::FEATURE_NOT_PRESENT},
677
678         PermissionsDelegationTestConfig{
679             ContentSettingsType::GEOLOCATION,
680             PermissionAction::GRANTED,
681             /*feature_overriden*/ absl::nullopt,
682             /*matches_all_origins*/ false,
683             {std::string(kCrossOriginFrameUrl)},
684             PermissionHeaderPolicyForUMA::
685                 FEATURE_ALLOWLIST_DOES_NOT_MATCH_ORIGIN}));
686
687 class CrossFramePermissionsDelegationUmaUtilTest
688     : public PermissionsDelegationUmaUtilTest {
689  public:
690   CrossFramePermissionsDelegationUmaUtilTest() = default;
691 };
692
693 TEST_P(CrossFramePermissionsDelegationUmaUtilTest, CrossOriginFrame) {
694   auto type = GetParam().type;
695   std::string permission_string = PermissionUtil::GetPermissionString(type);
696   // The histogram values should match with the ones defined in
697   // |permission_uma_util.cc|
698   std::string kUsageHistogramName =
699       base::StrCat({PermissionUmaUtil::kPermissionsExperimentalUsagePrefix,
700                     permission_string, ".IsCrossOriginFrame"});
701   std::string kCrossOriginFrameActionHistogramName =
702       base::StrCat({PermissionUmaUtil::kPermissionsActionPrefix,
703                     permission_string, ".CrossOriginFrame"});
704   std::string kPermissionsPolicyUsageHistogramName = base::StrCat(
705       {PermissionUmaUtil::kPermissionsExperimentalUsagePrefix,
706        permission_string, ".CrossOriginFrame.TopLevelHeaderPolicy"});
707   std::string kPermissionsPolicyActionHistogramName = base::StrCat(
708       {PermissionUmaUtil::kPermissionsActionPrefix, permission_string,
709        ".CrossOriginFrame.TopLevelHeaderPolicy"});
710
711   base::HistogramTester histograms;
712   auto* main_frame = GetMainFrameAndNavigate(kTopLevelUrl);
713   auto feature = PermissionUtil::GetPermissionsPolicyFeature(type);
714   blink::ParsedPermissionsPolicy top_policy;
715   if (feature.has_value() &&
716       (GetParam().matches_all_origins || !GetParam().origins.empty())) {
717     top_policy = CreatePermissionsPolicy(
718         GetParam().feature_overriden.has_value()
719             ? GetParam().feature_overriden.value()
720             : feature.value(),
721         GetParam().origins, GetParam().matches_all_origins);
722   }
723
724   if (!top_policy.empty()) {
725     RefreshAndSetPermissionsPolicy(&main_frame, top_policy);
726   }
727
728   // Add nested subframes A(B(C))
729   blink::ParsedPermissionsPolicy empty_policy;
730   auto* child_frame = AddChildFrameWithPermissionsPolicy(
731       main_frame, kCrossOriginFrameUrl,
732       feature.has_value()
733           ? CreatePermissionsPolicy(feature.value(),
734                                     {std::string(kCrossOriginFrameUrl)},
735                                     /*matches_all_origins*/ false)
736           : empty_policy);
737   child_frame = AddChildFrameWithPermissionsPolicy(
738       child_frame, kCrossOriginFrameUrl2,
739       feature.has_value()
740           ? CreatePermissionsPolicy(feature.value(),
741                                     {std::string(kCrossOriginFrameUrl2)},
742                                     /*matches_all_origins*/ false)
743           : empty_policy);
744   histograms.ExpectTotalCount(kUsageHistogramName, 0);
745   histograms.ExpectTotalCount(kPermissionsPolicyUsageHistogramName, 0);
746   histograms.ExpectTotalCount(kPermissionsPolicyActionHistogramName, 0);
747
748   PermissionUmaUtil::RecordPermissionsUsageSourceAndPolicyConfiguration(
749       type, child_frame);
750   EXPECT_THAT(histograms.GetAllSamples(kUsageHistogramName),
751               testing::ElementsAre(base::Bucket(1, 1)));
752   if (feature.has_value()) {
753     EXPECT_THAT(
754         histograms.GetAllSamples(kPermissionsPolicyUsageHistogramName),
755         testing::ElementsAre(base::Bucket(
756             static_cast<int>(GetParam().expected_configuration.value()), 1)));
757   } else {
758     histograms.ExpectTotalCount(kPermissionsPolicyUsageHistogramName, 0);
759   }
760
761   auto* permission_request_manager = SetupRequestManager(web_contents());
762   PermissionRequestWrapper* request_owner = new PermissionRequestWrapper(
763       permissions::ContentSettingsTypeToRequestType(type),
764       kCrossOriginFrameUrl2);
765   permission_request_manager->AddRequest(child_frame, request_owner->request());
766   PermissionUmaUtil::PermissionPromptResolved(
767       {request_owner->request()}, web_contents(), GetParam().action,
768       /*time_to_decision*/ base::TimeDelta(),
769       PermissionPromptDisposition::NOT_APPLICABLE,
770       /* ui_reason*/ absl::nullopt,
771       /*predicted_grant_likelihood*/ absl::nullopt,
772       /*prediction_decision_held_back*/ absl::nullopt,
773       /*ignored_reason*/ absl::nullopt, /*did_show_prompt*/ false,
774       /*did_click_managed*/ false,
775       /*did_click_learn_more*/ false);
776   if (feature.has_value()) {
777     EXPECT_THAT(
778         histograms.GetAllSamples(kPermissionsPolicyActionHistogramName),
779         testing::ElementsAre(base::Bucket(
780             static_cast<int>(GetParam().expected_configuration.value()), 1)));
781   } else {
782     histograms.ExpectTotalCount(kPermissionsPolicyActionHistogramName, 0);
783   }
784
785   EXPECT_THAT(histograms.GetAllSamples(kCrossOriginFrameActionHistogramName),
786               testing::ElementsAre(
787                   base::Bucket(static_cast<int>(GetParam().action), 1)));
788 }
789
790 INSTANTIATE_TEST_SUITE_P(
791     CrossOriginFrame,
792     CrossFramePermissionsDelegationUmaUtilTest,
793     testing::Values(
794         PermissionsDelegationTestConfig{
795             ContentSettingsType::GEOLOCATION, PermissionAction::GRANTED,
796             /*feature_overriden*/ absl::nullopt,
797             /*matches_all_origins*/ true,
798             /*origins*/ {},
799             PermissionHeaderPolicyForUMA::FEATURE_ALLOWLIST_IS_WILDCARD},
800
801         PermissionsDelegationTestConfig{
802             ContentSettingsType::GEOLOCATION,
803             PermissionAction::DENIED,
804             /*feature_overriden*/ absl::nullopt,
805             /*matches_all_origins*/ false,
806             {std::string(kTopLevelUrl), std::string(kCrossOriginFrameUrl),
807              std::string(kCrossOriginFrameUrl2)},
808             PermissionHeaderPolicyForUMA::
809                 FEATURE_ALLOWLIST_EXPLICITLY_MATCHES_ORIGIN},
810
811         PermissionsDelegationTestConfig{
812             ContentSettingsType::GEOLOCATION, PermissionAction::GRANTED,
813             /*feature_overriden*/ absl::nullopt,
814             /*matches_all_origins*/ false,
815             /*origins*/ {},
816             PermissionHeaderPolicyForUMA::HEADER_NOT_PRESENT_OR_INVALID},
817
818         PermissionsDelegationTestConfig{
819             ContentSettingsType::GEOLOCATION,
820             PermissionAction::GRANTED,
821             absl::make_optional<blink::mojom::PermissionsPolicyFeature>(
822                 blink::mojom::PermissionsPolicyFeature::kCamera),
823             /*matches_all_origins*/ false,
824             {std::string(kTopLevelUrl), std::string(kCrossOriginFrameUrl)},
825             PermissionHeaderPolicyForUMA::FEATURE_NOT_PRESENT},
826
827         PermissionsDelegationTestConfig{
828             ContentSettingsType::GEOLOCATION,
829             PermissionAction::DENIED,
830             /*feature_overriden*/ absl::nullopt,
831             /*matches_all_origins*/ false,
832             {std::string(kTopLevelUrl), std::string(kCrossOriginFrameUrl)},
833             PermissionHeaderPolicyForUMA::
834                 FEATURE_ALLOWLIST_DOES_NOT_MATCH_ORIGIN},
835
836         PermissionsDelegationTestConfig{
837             ContentSettingsType::ACCESSIBILITY_EVENTS, PermissionAction::DENIED,
838             /*feature_overriden*/ absl::nullopt,
839             /*matches_all_origins*/ true,
840             /*origins*/ {},
841             /*expected_configuration*/ absl::nullopt}));
842
843 class UkmRecorderPermissionUmaUtilTest
844     : public content::RenderViewHostTestHarness {
845  public:
846   void SetUp() override { content::RenderViewHostTestHarness::SetUp(); }
847
848   class UkmRecorderTestPermissionsClient : public TestPermissionsClient {
849    public:
850     UkmRecorderTestPermissionsClient() = default;
851
852     void SetSimulatedHasSourceId(bool source_id) {
853       simulated_has_source_id_ = source_id;
854     }
855
856     void GetUkmSourceId(content::BrowserContext* browser_context,
857                         content::WebContents* web_contents,
858                         const GURL& requesting_origin,
859                         GetUkmSourceIdCallback callback) override {
860       // Short circuit and return a null SourceId.
861       if (!simulated_has_source_id_) {
862         std::move(callback).Run(absl::nullopt);
863       } else {
864         ukm::SourceId fake_source_id =
865             ukm::ConvertToSourceId(1, ukm::SourceIdType::NAVIGATION_ID);
866         std::move(callback).Run(fake_source_id);
867       }
868     }
869
870    private:
871     bool simulated_has_source_id_ = false;
872   };
873
874   UkmRecorderTestPermissionsClient permissions_client_;
875 };
876
877 TEST_F(UkmRecorderPermissionUmaUtilTest,
878        NotificationRevocationHistogramDidRecordUkmTest) {
879   base::HistogramTester histograms;
880   content::TestBrowserContext browser_context;
881   ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
882   ukm::TestAutoSetUkmRecorder ukm_recorder;
883
884   permissions_client_.SetSimulatedHasSourceId(true);
885   const GURL origin(kTopLevelUrl);
886   PermissionUmaUtil::PermissionRevoked(
887       ContentSettingsType::NOTIFICATIONS,
888       permissions::PermissionSourceUI::ANDROID_SETTINGS, origin,
889       &browser_context);
890
891   histograms.ExpectBucketCount("Permissions.Action.Notifications",
892                                static_cast<int64_t>(PermissionAction::REVOKED),
893                                1);
894   histograms.ExpectBucketCount(
895       "Permissions.Revocation.Notifications.DidRecordUkm", 1, 1);
896   const auto entries = ukm_recorder.GetEntriesByName("Permission");
897   ASSERT_EQ(1u, entries.size());
898   const auto* entry = entries.back();
899   EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Action"),
900             static_cast<int64_t>(PermissionAction::REVOKED));
901 }
902
903 TEST_F(UkmRecorderPermissionUmaUtilTest,
904        NotificationRevocationHistogramDroppedUkmTest) {
905   base::HistogramTester histograms;
906   content::TestBrowserContext browser_context;
907   ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
908   ukm::TestAutoSetUkmRecorder ukm_recorder;
909
910   permissions_client_.SetSimulatedHasSourceId(false);
911   const GURL origin(kTopLevelUrl);
912   PermissionUmaUtil::PermissionRevoked(
913       ContentSettingsType::NOTIFICATIONS,
914       permissions::PermissionSourceUI::ANDROID_SETTINGS, origin,
915       &browser_context);
916
917   histograms.ExpectBucketCount("Permissions.Action.Notifications",
918                                static_cast<int64_t>(PermissionAction::REVOKED),
919                                1);
920
921   histograms.ExpectBucketCount(
922       "Permissions.Revocation.Notifications.DidRecordUkm", 0, 1);
923   const auto entries = ukm_recorder.GetEntriesByName("Permission");
924   EXPECT_EQ(0u, entries.size());
925 }
926
927 TEST_F(UkmRecorderPermissionUmaUtilTest,
928        NotificationUsageHistogramDidRecordUkmTest) {
929   base::HistogramTester histograms;
930   content::TestBrowserContext browser_context;
931   ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
932   ukm::TestAutoSetUkmRecorder ukm_recorder;
933
934   permissions_client_.SetSimulatedHasSourceId(true);
935   PermissionUmaUtil::RecordPermissionUsage(ContentSettingsType::NOTIFICATIONS,
936                                            &browser_context, web_contents(),
937                                            GURL(kTopLevelUrl));
938
939   histograms.ExpectBucketCount("Permissions.Usage.Notifications.DidRecordUkm",
940                                1, 1);
941   const auto entries = ukm_recorder.GetEntriesByName("PermissionUsage");
942   ASSERT_EQ(1u, entries.size());
943   const auto* entry = entries.back();
944   EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "PermissionType"),
945             content_settings_uma_util::ContentSettingTypeToHistogramValue(
946                 ContentSettingsType::NOTIFICATIONS));
947 }
948
949 TEST_F(UkmRecorderPermissionUmaUtilTest,
950        NotificationUsageHistogramDroppedUkmTest) {
951   base::HistogramTester histograms;
952   content::TestBrowserContext browser_context;
953
954   ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
955   ukm::TestAutoSetUkmRecorder ukm_recorder;
956
957   permissions_client_.SetSimulatedHasSourceId(false);
958   PermissionUmaUtil::RecordPermissionUsage(ContentSettingsType::NOTIFICATIONS,
959                                            &browser_context, web_contents(),
960                                            GURL(kTopLevelUrl));
961
962   histograms.ExpectBucketCount("Permissions.Usage.Notifications.DidRecordUkm",
963                                0, 1);
964   const auto entries = ukm_recorder.GetEntriesByName("PermissionUsage");
965   ASSERT_EQ(0u, entries.size());
966 }
967
968 }  // namespace permissions