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.
5 #include "components/permissions/permission_decision_auto_blocker.h"
10 #include "base/functional/bind.h"
11 #include "base/run_loop.h"
12 #include "base/test/gtest_util.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/test/simple_test_clock.h"
16 #include "components/content_settings/core/common/content_settings_types.h"
17 #include "components/permissions/features.h"
18 #include "components/permissions/permission_util.h"
19 #include "components/permissions/test/test_permissions_client.h"
20 #include "content/public/test/browser_task_environment.h"
21 #include "content/public/test/test_browser_context.h"
23 namespace permissions {
26 using PermissionStatus = blink::mojom::PermissionStatus;
28 bool FilterGoogle(const GURL& url) {
29 return url == "https://www.google.com/";
32 bool FilterAll(const GURL& url) {
38 class PermissionDecisionAutoBlockerUnitTest : public testing::Test {
40 PermissionDecisionAutoBlockerUnitTest() {
41 feature_list_.InitWithFeatures({features::kBlockPromptsIfDismissedOften,
42 features::kBlockPromptsIfIgnoredOften},
44 last_embargoed_status_ = false;
45 autoblocker()->SetClockForTesting(&clock_);
46 callback_was_run_ = false;
49 PermissionDecisionAutoBlocker* autoblocker() {
50 return PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
54 void SetLastEmbargoStatus(base::OnceClosure quit_closure, bool status) {
55 callback_was_run_ = true;
56 last_embargoed_status_ = status;
58 std::move(quit_closure).Run();
62 bool last_embargoed_status() { return last_embargoed_status_; }
64 bool callback_was_run() { return callback_was_run_; }
66 base::SimpleTestClock* clock() { return &clock_; }
69 content::BrowserTaskEnvironment task_environment_;
70 base::SimpleTestClock clock_;
71 base::test::ScopedFeatureList feature_list_;
72 content::TestBrowserContext browser_context_;
73 TestPermissionsClient permissions_client_;
74 bool last_embargoed_status_;
75 bool callback_was_run_;
78 class MockObserver : public PermissionDecisionAutoBlocker::Observer {
80 void OnEmbargoStarted(const GURL& origin,
81 ContentSettingsType content_setting) override {
82 callbacks_[origin].push_back(content_setting);
85 std::map<GURL, std::vector<ContentSettingsType>>& GetCallbacks() {
90 std::map<GURL, std::vector<ContentSettingsType>> callbacks_;
93 // Check removing the the embargo for a single permission on a site works, and
94 // that it doesn't interfere with other embargoed permissions or the same
95 // permission embargoed on other sites.
96 TEST_F(PermissionDecisionAutoBlockerUnitTest, RemoveEmbargoAndResetCounts) {
97 GURL url1("https://www.google.com");
98 GURL url2("https://www.example.com");
100 // Record dismissals for location and notifications in |url1|.
101 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
102 url1, ContentSettingsType::GEOLOCATION, false));
103 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
104 url1, ContentSettingsType::GEOLOCATION, false));
105 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
106 url1, ContentSettingsType::GEOLOCATION, false));
107 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
108 url1, ContentSettingsType::NOTIFICATIONS, false));
109 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
110 url1, ContentSettingsType::NOTIFICATIONS, false));
111 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
112 url1, ContentSettingsType::NOTIFICATIONS, false));
113 // Record dismissals for location in |url2|.
114 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
115 url2, ContentSettingsType::GEOLOCATION, false));
116 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
117 url2, ContentSettingsType::GEOLOCATION, false));
118 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
119 url2, ContentSettingsType::GEOLOCATION, false));
121 // Verify all dismissals recorded above resulted in embargo.
122 absl::optional<content::PermissionResult> result =
123 autoblocker()->GetEmbargoResult(url1, ContentSettingsType::GEOLOCATION);
124 EXPECT_EQ(PermissionStatus::DENIED, result->status);
125 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
128 autoblocker()->GetEmbargoResult(url1, ContentSettingsType::NOTIFICATIONS);
129 EXPECT_EQ(PermissionStatus::DENIED, result->status);
130 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
133 autoblocker()->GetEmbargoResult(url2, ContentSettingsType::GEOLOCATION);
134 EXPECT_EQ(PermissionStatus::DENIED, result->status);
135 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
138 // Remove the embargo on notifications. Verify it is no longer under embargo,
139 // but location still is.
140 autoblocker()->RemoveEmbargoAndResetCounts(
141 url1, ContentSettingsType::NOTIFICATIONS);
143 autoblocker()->GetEmbargoResult(url1, ContentSettingsType::GEOLOCATION);
144 EXPECT_EQ(PermissionStatus::DENIED, result->status);
145 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
148 autoblocker()->GetEmbargoResult(url1, ContentSettingsType::NOTIFICATIONS);
149 // If not under embargo, GetEmbargoResult() returns absl::nullopt.
150 EXPECT_FALSE(result.has_value());
151 // Verify |url2|'s embargo is still intact as well.
153 autoblocker()->GetEmbargoResult(url2, ContentSettingsType::GEOLOCATION);
154 EXPECT_EQ(PermissionStatus::DENIED, result->status);
155 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
159 // Test it does not take one more dismissal to re-trigger embargo after
160 // removing the embargo status for a site.
161 TEST_F(PermissionDecisionAutoBlockerUnitTest,
162 DismissAfterRemovingEmbargoByURL) {
163 GURL url("https://www.example.com");
165 // Record dismissals for location.
166 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
167 url, ContentSettingsType::GEOLOCATION, false));
168 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
169 url, ContentSettingsType::GEOLOCATION, false));
170 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
171 url, ContentSettingsType::GEOLOCATION, false));
173 // Verify location is under embargo.
174 absl::optional<content::PermissionResult> result =
175 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
176 EXPECT_EQ(PermissionStatus::DENIED, result->status);
177 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
180 // Remove embargo and verify this is true.
181 autoblocker()->RemoveEmbargoAndResetCounts(url,
182 ContentSettingsType::GEOLOCATION);
184 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
185 EXPECT_FALSE(result.has_value());
187 // Record another dismissal and verify location is not under embargo again.
188 autoblocker()->RecordDismissAndEmbargo(url, ContentSettingsType::GEOLOCATION,
191 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
192 EXPECT_FALSE(result.has_value());
195 TEST_F(PermissionDecisionAutoBlockerUnitTest,
196 NonembargoedOriginRemoveEmbargoCounts) {
197 GURL gurl_to_embargo("https://www.google.com");
199 // Make sure that an origin's Dismiss count is 0.
200 EXPECT_EQ(0, autoblocker()->GetDismissCount(
201 gurl_to_embargo, ContentSettingsType::GEOLOCATION));
203 // Dismiss the origin a few times but do not add under embargo.
204 autoblocker()->RecordDismissAndEmbargo(
205 gurl_to_embargo, ContentSettingsType::GEOLOCATION, false);
206 autoblocker()->RecordDismissAndEmbargo(
207 gurl_to_embargo, ContentSettingsType::GEOLOCATION, false);
209 EXPECT_EQ(2, autoblocker()->GetDismissCount(
210 gurl_to_embargo, ContentSettingsType::GEOLOCATION));
212 autoblocker()->RemoveEmbargoAndResetCounts(gurl_to_embargo,
213 ContentSettingsType::GEOLOCATION);
215 EXPECT_EQ(0, autoblocker()->GetDismissCount(
216 gurl_to_embargo, ContentSettingsType::GEOLOCATION));
218 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
219 ContentSettingsType::MIDI_SYSEX, false);
220 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
221 ContentSettingsType::MIDI_SYSEX, false);
223 EXPECT_EQ(2, autoblocker()->GetIgnoreCount(gurl_to_embargo,
224 ContentSettingsType::MIDI_SYSEX));
226 autoblocker()->RemoveEmbargoAndResetCounts(gurl_to_embargo,
227 ContentSettingsType::MIDI_SYSEX);
229 EXPECT_EQ(0, autoblocker()->GetIgnoreCount(gurl_to_embargo,
230 ContentSettingsType::MIDI_SYSEX));
233 TEST_F(PermissionDecisionAutoBlockerUnitTest, RemoveEmbargoCounts) {
234 GURL gurl_to_embargo("https://www.google.com");
236 // Add an origin under embargo for 2 dismissed and 1 ignored
237 // ContentSettingsType.
238 autoblocker()->RecordDismissAndEmbargo(
239 gurl_to_embargo, ContentSettingsType::GEOLOCATION, false);
240 autoblocker()->RecordDismissAndEmbargo(
241 gurl_to_embargo, ContentSettingsType::GEOLOCATION, false);
242 autoblocker()->RecordDismissAndEmbargo(
243 gurl_to_embargo, ContentSettingsType::GEOLOCATION, false);
245 EXPECT_EQ(3, autoblocker()->GetDismissCount(
246 gurl_to_embargo, ContentSettingsType::GEOLOCATION));
248 autoblocker()->RecordDismissAndEmbargo(
249 gurl_to_embargo, ContentSettingsType::NOTIFICATIONS, false);
250 autoblocker()->RecordDismissAndEmbargo(
251 gurl_to_embargo, ContentSettingsType::NOTIFICATIONS, false);
252 autoblocker()->RecordDismissAndEmbargo(
253 gurl_to_embargo, ContentSettingsType::NOTIFICATIONS, false);
255 EXPECT_EQ(3, autoblocker()->GetDismissCount(
256 gurl_to_embargo, ContentSettingsType::NOTIFICATIONS));
258 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
259 ContentSettingsType::MIDI_SYSEX, false);
260 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
261 ContentSettingsType::MIDI_SYSEX, false);
262 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
263 ContentSettingsType::MIDI_SYSEX, false);
264 autoblocker()->RecordIgnoreAndEmbargo(gurl_to_embargo,
265 ContentSettingsType::MIDI_SYSEX, false);
267 EXPECT_EQ(4, autoblocker()->GetIgnoreCount(gurl_to_embargo,
268 ContentSettingsType::MIDI_SYSEX));
270 autoblocker()->RemoveEmbargoAndResetCounts(gurl_to_embargo,
271 ContentSettingsType::GEOLOCATION);
273 // GEOLOCATION has been cleared, a dismiss count should be 0.
274 EXPECT_EQ(0, autoblocker()->GetDismissCount(
275 gurl_to_embargo, ContentSettingsType::GEOLOCATION));
276 // GEOLOCATION has been cleared, but other counts should be
278 EXPECT_EQ(3, autoblocker()->GetDismissCount(
279 gurl_to_embargo, ContentSettingsType::NOTIFICATIONS));
280 EXPECT_EQ(4, autoblocker()->GetIgnoreCount(gurl_to_embargo,
281 ContentSettingsType::MIDI_SYSEX));
284 TEST_F(PermissionDecisionAutoBlockerUnitTest, RemoveEmbargoAndResetCounts_All) {
285 GURL url1("https://www.google.com");
286 GURL url2("https://www.example.com");
288 // Record some dismissals.
289 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
290 url1, ContentSettingsType::GEOLOCATION, false));
291 EXPECT_EQ(1, autoblocker()->GetDismissCount(
292 url1, ContentSettingsType::GEOLOCATION));
294 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
295 url1, ContentSettingsType::GEOLOCATION, false));
296 EXPECT_EQ(2, autoblocker()->GetDismissCount(
297 url1, ContentSettingsType::GEOLOCATION));
299 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
300 url1, ContentSettingsType::GEOLOCATION, false));
301 EXPECT_EQ(3, autoblocker()->GetDismissCount(
302 url1, ContentSettingsType::GEOLOCATION));
304 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
305 url2, ContentSettingsType::GEOLOCATION, false));
306 EXPECT_EQ(1, autoblocker()->GetDismissCount(
307 url2, ContentSettingsType::GEOLOCATION));
309 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
310 url1, ContentSettingsType::NOTIFICATIONS, false));
311 EXPECT_EQ(1, autoblocker()->GetDismissCount(
312 url1, ContentSettingsType::NOTIFICATIONS));
314 // Record some ignores.
315 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
316 url1, ContentSettingsType::MIDI_SYSEX, false));
318 1, autoblocker()->GetIgnoreCount(url1, ContentSettingsType::MIDI_SYSEX));
319 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
320 url1, ContentSettingsType::DURABLE_STORAGE, false));
321 EXPECT_EQ(1, autoblocker()->GetIgnoreCount(
322 url1, ContentSettingsType::DURABLE_STORAGE));
323 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
324 url2, ContentSettingsType::GEOLOCATION, false));
325 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
326 url2, ContentSettingsType::GEOLOCATION, false));
328 2, autoblocker()->GetIgnoreCount(url2, ContentSettingsType::GEOLOCATION));
330 autoblocker()->RemoveEmbargoAndResetCounts(
331 base::BindRepeating(&FilterGoogle));
333 // Expect that url1's actions are gone, but url2's remain.
334 EXPECT_EQ(0, autoblocker()->GetDismissCount(
335 url1, ContentSettingsType::GEOLOCATION));
336 EXPECT_EQ(0, autoblocker()->GetDismissCount(
337 url1, ContentSettingsType::NOTIFICATIONS));
339 0, autoblocker()->GetIgnoreCount(url1, ContentSettingsType::MIDI_SYSEX));
340 EXPECT_EQ(0, autoblocker()->GetIgnoreCount(
341 url1, ContentSettingsType::DURABLE_STORAGE));
343 EXPECT_EQ(1, autoblocker()->GetDismissCount(
344 url2, ContentSettingsType::GEOLOCATION));
346 2, autoblocker()->GetIgnoreCount(url2, ContentSettingsType::GEOLOCATION));
348 // Add some more actions.
349 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
350 url1, ContentSettingsType::GEOLOCATION, false));
351 EXPECT_EQ(1, autoblocker()->GetDismissCount(
352 url1, ContentSettingsType::GEOLOCATION));
354 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
355 url1, ContentSettingsType::NOTIFICATIONS, false));
356 EXPECT_EQ(1, autoblocker()->GetDismissCount(
357 url1, ContentSettingsType::NOTIFICATIONS));
359 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
360 url2, ContentSettingsType::GEOLOCATION, false));
361 EXPECT_EQ(2, autoblocker()->GetDismissCount(
362 url2, ContentSettingsType::GEOLOCATION));
364 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
365 url1, ContentSettingsType::GEOLOCATION, false));
367 1, autoblocker()->GetIgnoreCount(url1, ContentSettingsType::GEOLOCATION));
368 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
369 url1, ContentSettingsType::NOTIFICATIONS, false));
370 EXPECT_EQ(1, autoblocker()->GetIgnoreCount(
371 url1, ContentSettingsType::NOTIFICATIONS));
372 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
373 url1, ContentSettingsType::DURABLE_STORAGE, false));
374 EXPECT_EQ(1, autoblocker()->GetIgnoreCount(
375 url1, ContentSettingsType::DURABLE_STORAGE));
376 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
377 url2, ContentSettingsType::MIDI_SYSEX, false));
379 1, autoblocker()->GetIgnoreCount(url2, ContentSettingsType::MIDI_SYSEX));
381 // Remove everything and expect that it's all gone.
382 autoblocker()->RemoveEmbargoAndResetCounts(base::BindRepeating(&FilterAll));
384 EXPECT_EQ(0, autoblocker()->GetDismissCount(
385 url1, ContentSettingsType::GEOLOCATION));
386 EXPECT_EQ(0, autoblocker()->GetDismissCount(
387 url1, ContentSettingsType::NOTIFICATIONS));
388 EXPECT_EQ(0, autoblocker()->GetDismissCount(
389 url2, ContentSettingsType::GEOLOCATION));
392 0, autoblocker()->GetIgnoreCount(url1, ContentSettingsType::GEOLOCATION));
393 EXPECT_EQ(0, autoblocker()->GetIgnoreCount(
394 url1, ContentSettingsType::NOTIFICATIONS));
396 0, autoblocker()->GetIgnoreCount(url2, ContentSettingsType::GEOLOCATION));
397 EXPECT_EQ(0, autoblocker()->GetIgnoreCount(
398 url2, ContentSettingsType::DURABLE_STORAGE));
400 0, autoblocker()->GetIgnoreCount(url2, ContentSettingsType::MIDI_SYSEX));
403 // Check that GetEmbargoedOrigins only returns origins where embargo is the
404 // effective permission enforcement mechanism.
405 TEST_F(PermissionDecisionAutoBlockerUnitTest, CheckEmbargoedOrigins) {
406 GURL url1("https://www.google.com");
407 GURL url2("https://www.google.com:8443");
408 std::vector<ContentSettingsType> content_types = {
409 ContentSettingsType::GEOLOCATION, ContentSettingsType::NOTIFICATIONS};
410 std::set<GURL> origins;
411 clock()->SetNow(base::Time::Now());
413 EXPECT_EQ(0UL, autoblocker()->GetEmbargoedOrigins(content_types).size());
415 // Place both origins under embargo and verify.
416 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
417 url1, ContentSettingsType::GEOLOCATION, false));
418 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
419 url1, ContentSettingsType::GEOLOCATION, false));
420 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
421 url1, ContentSettingsType::GEOLOCATION, false));
422 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
423 url2, ContentSettingsType::NOTIFICATIONS, false));
424 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
425 url2, ContentSettingsType::NOTIFICATIONS, false));
426 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
427 url2, ContentSettingsType::NOTIFICATIONS, false));
429 origins = autoblocker()->GetEmbargoedOrigins(content_types);
430 EXPECT_EQ(2UL, origins.size());
431 EXPECT_EQ(1UL, origins.count(url1));
432 EXPECT_EQ(1UL, origins.count(url2));
434 // Check no leakage between content types
436 autoblocker()->GetEmbargoedOrigins(ContentSettingsType::GEOLOCATION);
437 EXPECT_EQ(1UL, origins.count(url1));
439 autoblocker()->GetEmbargoedOrigins(ContentSettingsType::NOTIFICATIONS);
440 EXPECT_EQ(1UL, origins.count(url2));
442 // Remove an embargo and confirm it's removed from origins
443 autoblocker()->RemoveEmbargoAndResetCounts(url1,
444 ContentSettingsType::GEOLOCATION);
445 origins = autoblocker()->GetEmbargoedOrigins(content_types);
446 EXPECT_EQ(1UL, origins.size());
447 EXPECT_EQ(1UL, origins.count(url2));
449 // Expire the remaining embargo and confirm the origin is removed
450 clock()->Advance(base::Days(8));
451 origins = autoblocker()->GetEmbargoedOrigins(content_types);
452 EXPECT_EQ(0UL, origins.size());
455 // Check that GetEmbargoResult returns the correct value when the embargo is set
457 TEST_F(PermissionDecisionAutoBlockerUnitTest, CheckEmbargoStatus) {
458 GURL url("https://www.google.com");
459 clock()->SetNow(base::Time::Now());
461 // Check the default state.
462 absl::optional<content::PermissionResult> result =
463 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
464 EXPECT_FALSE(result.has_value());
466 // Place under embargo and verify.
467 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
468 url, ContentSettingsType::GEOLOCATION, false));
469 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
470 url, ContentSettingsType::GEOLOCATION, false));
471 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
472 url, ContentSettingsType::GEOLOCATION, false));
474 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
475 EXPECT_EQ(PermissionStatus::DENIED, result->status);
476 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
479 // Check that the origin is not under embargo for a different permission.
481 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
482 EXPECT_FALSE(result.has_value());
484 // Confirm embargo status during the embargo period.
485 clock()->Advance(base::Days(5));
487 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
488 EXPECT_EQ(PermissionStatus::DENIED, result->status);
489 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
492 // Check embargo is lifted on expiry day. A small offset after the exact
493 // embargo expiration date has been added to account for any precision errors
494 // when removing the date stored as a double from the permission dictionary.
495 clock()->Advance(base::Hours(3 * 24 + 1));
497 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
498 EXPECT_FALSE(result.has_value());
500 // Check embargo is lifted well after the expiry day.
501 clock()->Advance(base::Days(1));
503 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
504 EXPECT_FALSE(result.has_value());
506 // Place under embargo again and verify the embargo status.
507 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
508 url, ContentSettingsType::NOTIFICATIONS, false));
509 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
510 url, ContentSettingsType::NOTIFICATIONS, false));
511 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
512 url, ContentSettingsType::NOTIFICATIONS, false));
513 clock()->Advance(base::Days(1));
515 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
516 EXPECT_EQ(PermissionStatus::DENIED, result->status);
517 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
520 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
521 EXPECT_FALSE(result.has_value());
524 // Check that GetEmbargoStartTime returns the correct time for embargoes whether
525 // they are nonexistent, expired or active.
526 TEST_F(PermissionDecisionAutoBlockerUnitTest, CheckEmbargoStartTime) {
527 GURL url("https://www.google.com");
529 // The time recorded for embargoes will be stored as a double, which will
530 // cause aliasing to a limited set of base::Time values upon retrieval. We
531 // thus pick a base::Time for our test time that is part of this set via
532 // aliasing the current time by passing it through a double. This allows us
533 // to directly compare the test time and times retrieved from storage.
534 base::Time test_time = base::Time::FromDeltaSinceWindowsEpoch(
535 base::Microseconds(static_cast<double>(
536 base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds())));
537 clock()->SetNow(test_time);
539 // Check the default non embargod state.
540 base::Time embargo_start_time =
541 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
542 EXPECT_EQ(base::Time(), embargo_start_time);
544 // Ensure that dismissing less than the required number for an embargo
545 // does not record an embargo start time.
546 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
547 url, ContentSettingsType::GEOLOCATION, false));
549 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
550 EXPECT_EQ(base::Time(), embargo_start_time);
552 // Place site under geolocation dismissal embargo.
553 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
554 url, ContentSettingsType::GEOLOCATION, false));
555 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
556 url, ContentSettingsType::GEOLOCATION, false));
558 // Confirm embargo is recorded as starting at the correct time.
560 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
561 EXPECT_EQ(test_time, embargo_start_time);
563 // Ensure moving clock while within embargo period does not affect embargo
565 clock()->Advance(base::Days(5));
567 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
568 EXPECT_EQ(test_time, embargo_start_time);
570 // Move clock beyond embaro (plus a small offset for potential precision
571 // errors) and confirm start time is unaffected but embargo is suspended.
572 clock()->Advance(base::Hours(3 * 24 + 1));
574 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
575 EXPECT_EQ(test_time, embargo_start_time);
576 absl::optional<content::PermissionResult> result =
577 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
578 EXPECT_FALSE(result.has_value());
580 // Advance time, reinstate embargo and confirm that time is updated.
581 test_time += base::Days(9);
582 test_time = base::Time::FromDeltaSinceWindowsEpoch(
583 base::Microseconds(static_cast<double>(
584 test_time.ToDeltaSinceWindowsEpoch().InMicroseconds())));
585 clock()->SetNow(test_time);
587 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
588 url, ContentSettingsType::GEOLOCATION, false));
590 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
591 EXPECT_EQ(test_time, embargo_start_time);
593 // Advance time to expire dismiss embargo and create new embargo for ignoring.
594 test_time += base::Days(7);
595 test_time = base::Time::FromDeltaSinceWindowsEpoch(
596 base::Microseconds(static_cast<double>(
597 test_time.ToDeltaSinceWindowsEpoch().InMicroseconds())));
598 clock()->SetNow(test_time);
600 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
601 url, ContentSettingsType::GEOLOCATION, false));
602 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
603 url, ContentSettingsType::GEOLOCATION, false));
604 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
605 url, ContentSettingsType::GEOLOCATION, false));
606 EXPECT_TRUE(autoblocker()->RecordIgnoreAndEmbargo(
607 url, ContentSettingsType::GEOLOCATION, false));
609 // Confirm the most recent embargo is updated to match new ignore embargo.
611 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
612 EXPECT_EQ(test_time, embargo_start_time);
614 // Advance time, reinstate the dismiss embargo via a single action, and
615 // confirm that time is updated.
616 test_time += base::Days(1);
617 test_time = base::Time::FromDeltaSinceWindowsEpoch(
618 base::Microseconds(static_cast<double>(
619 test_time.ToDeltaSinceWindowsEpoch().InMicroseconds())));
620 clock()->SetNow(test_time);
622 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
623 url, ContentSettingsType::GEOLOCATION, false));
625 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
626 EXPECT_EQ(test_time, embargo_start_time);
628 // Remove records of dismiss and ignore embargoes and confirm start time
629 // reverts to default.
630 autoblocker()->RemoveEmbargoAndResetCounts(
631 base::BindRepeating(&FilterGoogle));
633 autoblocker()->GetEmbargoStartTime(url, ContentSettingsType::GEOLOCATION);
634 EXPECT_EQ(base::Time(), embargo_start_time);
637 // Tests the alternating pattern of the block on multiple dismiss behaviour. On
638 // N dismissals, the origin to be embargoed for the requested permission and
639 // automatically blocked. Each time the embargo is lifted, the site gets another
640 // chance to request the permission, but if it is again dismissed it is placed
641 // under embargo again and its permission requests blocked.
642 TEST_F(PermissionDecisionAutoBlockerUnitTest, TestDismissEmbargoBackoff) {
643 GURL url("https://www.google.com");
644 clock()->SetNow(base::Time::Now());
645 base::HistogramTester histograms;
647 // Record some dismisses.
648 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
649 url, ContentSettingsType::GEOLOCATION, false));
650 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
651 url, ContentSettingsType::GEOLOCATION, false));
653 // A request with < 3 prior dismisses should not be automatically blocked.
654 absl::optional<content::PermissionResult> result =
655 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
656 EXPECT_FALSE(result.has_value());
658 // After the 3rd dismiss subsequent permission requests should be autoblocked.
659 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
660 url, ContentSettingsType::GEOLOCATION, false));
662 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
663 EXPECT_EQ(PermissionStatus::DENIED, result->status);
664 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
667 // Accelerate time forward, check that the embargo status is lifted and the
668 // request won't be automatically blocked.
669 clock()->Advance(base::Days(8));
671 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
672 EXPECT_FALSE(result.has_value());
674 // Record another dismiss, subsequent requests should be autoblocked again.
675 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
676 url, ContentSettingsType::GEOLOCATION, false));
678 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
679 EXPECT_EQ(PermissionStatus::DENIED, result->status);
680 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
683 // Accelerate time again, check embargo is lifted and another permission
684 // request is let through.
685 clock()->Advance(base::Days(8));
687 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
688 EXPECT_FALSE(result.has_value());
690 // Record another dismiss, subsequent requests should be autoblocked again.
691 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
692 url, ContentSettingsType::GEOLOCATION, false));
694 autoblocker()->GetEmbargoResult(url, ContentSettingsType::GEOLOCATION);
695 EXPECT_EQ(PermissionStatus::DENIED, result->status);
696 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
700 // Tests the alternating pattern of the block on multiple ignores behaviour.
701 TEST_F(PermissionDecisionAutoBlockerUnitTest, TestIgnoreEmbargoBackoff) {
702 GURL url("https://www.google.com");
703 clock()->SetNow(base::Time::Now());
704 base::HistogramTester histograms;
706 // Record some ignores.
707 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
708 url, ContentSettingsType::MIDI_SYSEX, false));
709 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
710 url, ContentSettingsType::MIDI_SYSEX, false));
712 // A request with < 4 prior ignores should not be automatically blocked.
713 absl::optional<content::PermissionResult> result =
714 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
715 EXPECT_FALSE(result.has_value());
717 // After the 4th ignore subsequent permission requests should be autoblocked.
718 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
719 url, ContentSettingsType::MIDI_SYSEX, false));
720 EXPECT_TRUE(autoblocker()->RecordIgnoreAndEmbargo(
721 url, ContentSettingsType::MIDI_SYSEX, false));
723 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
724 EXPECT_EQ(PermissionStatus::DENIED, result->status);
725 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_IGNORES, result->source);
727 // Accelerate time forward, check that the embargo status is lifted and the
728 // request won't be automatically blocked.
729 clock()->Advance(base::Days(8));
731 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
732 EXPECT_FALSE(result.has_value());
734 // Record another dismiss, subsequent requests should be autoblocked again.
735 EXPECT_TRUE(autoblocker()->RecordIgnoreAndEmbargo(
736 url, ContentSettingsType::MIDI_SYSEX, false));
738 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
739 EXPECT_EQ(PermissionStatus::DENIED, result->status);
740 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_IGNORES, result->source);
742 // Accelerate time again, check embargo is lifted and another permission
743 // request is let through.
744 clock()->Advance(base::Days(8));
746 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
747 EXPECT_FALSE(result.has_value());
749 // Record another dismiss, subsequent requests should be autoblocked again.
750 EXPECT_TRUE(autoblocker()->RecordIgnoreAndEmbargo(
751 url, ContentSettingsType::MIDI_SYSEX, false));
753 autoblocker()->GetEmbargoResult(url, ContentSettingsType::MIDI_SYSEX);
754 EXPECT_EQ(PermissionStatus::DENIED, result->status);
755 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_IGNORES, result->source);
758 // Test that quiet ui embargo has a different threshold for ignores.
759 TEST_F(PermissionDecisionAutoBlockerUnitTest, TestIgnoreEmbargoUsingQuietUi) {
760 GURL url("https://www.google.com");
761 clock()->SetNow(base::Time::Now());
763 // Check the default state.
764 absl::optional<content::PermissionResult> result =
765 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
766 EXPECT_FALSE(result.has_value());
768 // One quiet ui ignore is not enough to trigger embargo.
769 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
770 url, ContentSettingsType::NOTIFICATIONS, true));
772 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
773 EXPECT_FALSE(result.has_value());
775 // Loud ui ignores are counted separately.
776 EXPECT_FALSE(autoblocker()->RecordIgnoreAndEmbargo(
777 url, ContentSettingsType::NOTIFICATIONS, false));
779 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
780 EXPECT_FALSE(result.has_value());
782 // The second quiet ui ignore puts the url under embargo.
783 EXPECT_TRUE(autoblocker()->RecordIgnoreAndEmbargo(
784 url, ContentSettingsType::NOTIFICATIONS, true));
786 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
787 EXPECT_EQ(PermissionStatus::DENIED, result->status);
788 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_IGNORES, result->source);
791 // Test that quiet ui embargo has a different threshold for dismisses.
792 TEST_F(PermissionDecisionAutoBlockerUnitTest, TestDismissEmbargoUsingQuietUi) {
793 GURL url("https://www.google.com");
794 clock()->SetNow(base::Time::Now());
796 // Check the default state.
797 absl::optional<content::PermissionResult> result =
798 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
799 EXPECT_FALSE(result.has_value());
801 // One loud ui dismiss does not trigger embargo.
802 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
803 url, ContentSettingsType::NOTIFICATIONS, false));
805 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
806 EXPECT_FALSE(result.has_value());
808 // One quiet ui dismiss puts the url under embargo.
809 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
810 url, ContentSettingsType::NOTIFICATIONS, true));
812 autoblocker()->GetEmbargoResult(url, ContentSettingsType::NOTIFICATIONS);
813 EXPECT_EQ(PermissionStatus::DENIED, result->status);
814 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
820 // Checks that embargo on federated identity permission is lifted only after the
821 // passed-in |time_delta| has elapsed.
822 void CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
823 PermissionDecisionAutoBlocker* autoblocker,
824 base::SimpleTestClock* clock,
826 base::TimeDelta time_delta) {
827 ASSERT_LT(base::Minutes(1), time_delta);
829 clock->Advance(time_delta - base::Minutes(1));
830 absl::optional<content::PermissionResult> result =
831 autoblocker->GetEmbargoResult(
832 url, ContentSettingsType::FEDERATED_IDENTITY_API);
833 EXPECT_EQ(PermissionStatus::DENIED, result->status);
834 EXPECT_EQ(content::PermissionStatusSource::MULTIPLE_DISMISSALS,
837 clock->Advance(base::Minutes(2));
838 result = autoblocker->GetEmbargoResult(
839 url, ContentSettingsType::FEDERATED_IDENTITY_API);
840 EXPECT_FALSE(result.has_value());
843 // Checks that embargo on federated identity auto re-authn permission is lifted
844 // only after the passed-in |time_delta| has elapsed.
845 void CheckFederatedIdentityAutoReauthnEmbargoLiftedAfterTimeElapsing(
846 PermissionDecisionAutoBlocker* autoblocker,
847 base::SimpleTestClock* clock,
849 base::TimeDelta time_delta) {
850 ASSERT_LT(base::Minutes(1), time_delta);
852 clock->Advance(time_delta - base::Minutes(1));
853 absl::optional<content::PermissionResult> result =
854 autoblocker->GetEmbargoResult(
855 url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION);
856 EXPECT_EQ(PermissionStatus::DENIED, result->status);
857 EXPECT_EQ(content::PermissionStatusSource::RECENT_DISPLAY, result->source);
859 clock->Advance(base::Minutes(2));
860 result = autoblocker->GetEmbargoResult(
861 url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION);
862 EXPECT_FALSE(result.has_value());
867 TEST_F(PermissionDecisionAutoBlockerUnitTest,
868 TestDismissFederatedIdentityApiBackoff) {
869 GURL url("https://www.google.com");
870 clock()->SetNow(base::Time::Now());
872 absl::optional<content::PermissionResult> result =
873 autoblocker()->GetEmbargoResult(
874 url, ContentSettingsType::FEDERATED_IDENTITY_API);
875 EXPECT_FALSE(result.has_value());
877 // 2 hour embargo for 1st dismissal
878 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
879 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
880 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
881 autoblocker(), clock(), url, base::Hours(2));
883 // 1 day embargo for 2nd dismissal
884 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
885 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
886 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
887 autoblocker(), clock(), url, base::Days(1));
889 // 7 day embargo for 3rd dismissal
890 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
891 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
892 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
893 autoblocker(), clock(), url, base::Days(7));
895 // 28 day embargo for 4th dismissal (and all additional dismissals)
896 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
897 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
898 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
899 autoblocker(), clock(), url, base::Days(28));
901 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
902 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
903 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
904 autoblocker(), clock(), url, base::Days(28));
906 // Return to 2 hour embargo after
907 // PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts()
908 autoblocker()->RemoveEmbargoAndResetCounts(
909 url, ContentSettingsType::FEDERATED_IDENTITY_API);
910 result = autoblocker()->GetEmbargoResult(
911 url, ContentSettingsType::FEDERATED_IDENTITY_API);
912 EXPECT_FALSE(result.has_value());
914 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
915 url, ContentSettingsType::FEDERATED_IDENTITY_API, false));
916 CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
917 autoblocker(), clock(), url, base::Hours(2));
920 TEST_F(PermissionDecisionAutoBlockerUnitTest,
921 TestLogoutFederatedIdentityAutoReauthnBackoff) {
922 GURL url("https://www.google.com");
923 clock()->SetNow(base::Time::Now());
925 absl::optional<content::PermissionResult> result =
926 autoblocker()->GetEmbargoResult(
927 url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION);
928 EXPECT_FALSE(result.has_value());
931 EXPECT_TRUE(autoblocker()->RecordDisplayAndEmbargo(
932 url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION));
933 CheckFederatedIdentityAutoReauthnEmbargoLiftedAfterTimeElapsing(
934 autoblocker(), clock(), url, base::Minutes(10));
937 TEST_F(PermissionDecisionAutoBlockerUnitTest,
938 ObserverIsNotifiedWhenEmbargoStarts) {
939 GURL url("https://www.google.com");
940 MockObserver observer;
941 autoblocker()->AddObserver(&observer);
943 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
944 url, ContentSettingsType::GEOLOCATION, false));
945 EXPECT_EQ(0u, observer.GetCallbacks().size());
947 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
948 url, ContentSettingsType::GEOLOCATION, false));
949 EXPECT_EQ(0u, observer.GetCallbacks().size());
951 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
952 url, ContentSettingsType::GEOLOCATION, false));
953 EXPECT_EQ(1u, observer.GetCallbacks().size());
954 EXPECT_EQ(url, observer.GetCallbacks().begin()->first);
955 EXPECT_EQ(ContentSettingsType::GEOLOCATION, observer.GetCallbacks()[url][0]);
957 autoblocker()->RemoveObserver(&observer);
960 TEST_F(PermissionDecisionAutoBlockerUnitTest,
961 RemovedObserverIsNotNotifiedWhenEmbargoStarts) {
962 GURL url("https://www.google.com");
963 MockObserver observer;
964 autoblocker()->AddObserver(&observer);
966 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
967 url, ContentSettingsType::GEOLOCATION, false));
968 EXPECT_EQ(0u, observer.GetCallbacks().size());
970 EXPECT_FALSE(autoblocker()->RecordDismissAndEmbargo(
971 url, ContentSettingsType::GEOLOCATION, false));
972 EXPECT_EQ(0u, observer.GetCallbacks().size());
973 autoblocker()->RemoveObserver(&observer);
975 EXPECT_TRUE(autoblocker()->RecordDismissAndEmbargo(
976 url, ContentSettingsType::GEOLOCATION, false));
977 EXPECT_EQ(0u, observer.GetCallbacks().size());
980 } // namespace permissions