1 // Copyright 2015 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_manager.h"
9 #include "base/functional/bind.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/field_trial_params.h"
13 #include "build/build_config.h"
14 #include "build/chromeos_buildflags.h"
15 #include "components/content_settings/core/browser/host_content_settings_map.h"
16 #include "components/permissions/features.h"
17 #include "components/permissions/permission_context_base.h"
18 #include "components/permissions/permission_request_manager.h"
19 #include "components/permissions/permission_util.h"
20 #include "components/permissions/test/mock_permission_prompt_factory.h"
21 #include "components/permissions/test/permission_test_util.h"
22 #include "components/permissions/test/test_permissions_client.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/permission_request_description.h"
25 #include "content/public/browser/permission_result.h"
26 #include "content/public/common/content_client.h"
27 #include "content/public/test/browser_task_environment.h"
28 #include "content/public/test/mock_render_process_host.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 "testing/gtest/include/gtest/gtest.h"
33 #include "third_party/blink/public/common/permissions/permission_utils.h"
34 #include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
35 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
36 #include "url/origin.h"
38 using blink::PermissionType;
39 using blink::mojom::PermissionsPolicyFeature;
41 namespace permissions {
44 class ScopedPartitionedOriginBrowserClient
45 : public content::ContentBrowserClient {
47 explicit ScopedPartitionedOriginBrowserClient(const GURL& app_origin)
48 : app_origin_(url::Origin::Create(app_origin)) {
49 old_client_ = content::SetBrowserClientForTesting(this);
52 ~ScopedPartitionedOriginBrowserClient() override {
53 content::SetBrowserClientForTesting(old_client_);
56 content::StoragePartitionConfig GetStoragePartitionConfigForSite(
57 content::BrowserContext* browser_context,
58 const GURL& site) override {
59 if (url::Origin::Create(site) == app_origin_) {
60 return content::StoragePartitionConfig::Create(
61 browser_context, "test_partition", /*partition_name=*/std::string(),
64 return content::StoragePartitionConfig::CreateDefault(browser_context);
68 url::Origin app_origin_;
69 raw_ptr<content::ContentBrowserClient> old_client_;
74 class PermissionManagerTest : public content::RenderViewHostTestHarness {
76 void OnPermissionChange(PermissionStatus permission) {
77 if (!quit_closure_.is_null())
78 std::move(quit_closure_).Run();
79 callback_called_ = true;
81 callback_result_ = permission;
85 PermissionManagerTest()
86 : url_("https://example.com"), other_url_("https://foo.com") {}
88 PermissionManager* GetPermissionManager() {
89 return static_cast<PermissionManager*>(
90 browser_context_->GetPermissionControllerDelegate());
93 HostContentSettingsMap* GetHostContentSettingsMap() {
94 return PermissionsClient::Get()->GetSettingsMap(browser_context_.get());
97 void CheckPermissionStatus(PermissionType type, PermissionStatus expected) {
98 EXPECT_EQ(expected, GetPermissionManager()
99 ->GetPermissionResultForOriginWithoutContext(
100 type, url::Origin::Create(url_),
101 url::Origin::Create(url_))
105 void CheckPermissionResult(
107 PermissionStatus expected_status,
108 content::PermissionStatusSource expected_status_source) {
109 content::PermissionResult result =
110 GetPermissionManager()->GetPermissionResultForOriginWithoutContext(
111 type, url::Origin::Create(url_), url::Origin::Create(url_));
112 EXPECT_EQ(expected_status, result.status);
113 EXPECT_EQ(expected_status_source, result.source);
116 void SetPermission(PermissionType type, PermissionStatus value) {
117 SetPermission(url_, url_, type, value);
120 void SetPermission(const GURL& origin,
122 PermissionStatus value) {
123 SetPermission(origin, origin, type, value);
126 void SetPermission(const GURL& requesting_origin,
127 const GURL& embedding_origin,
129 PermissionStatus value) {
130 GetHostContentSettingsMap()->SetContentSettingDefaultScope(
131 requesting_origin, embedding_origin,
132 permissions::PermissionUtil::PermissionTypeToContentSettingType(type),
133 permissions::PermissionUtil::PermissionStatusToContentSetting(value));
136 void RequestPermissionFromCurrentDocument(PermissionType type,
137 content::RenderFrameHost* rfh) {
139 quit_closure_ = loop.QuitClosure();
140 GetPermissionManager()->RequestPermissionsFromCurrentDocument(
142 std::move(content::PermissionRequestDescription(
143 std::vector(1, type),
144 /*user_gesture=*/true, rfh->GetLastCommittedOrigin().GetURL())),
146 [](base::OnceCallback<void(PermissionStatus)> callback,
147 const std::vector<PermissionStatus>& state) {
148 DCHECK_EQ(state.size(), 1U);
149 std::move(callback).Run(state[0]);
151 base::BindOnce(&PermissionManagerTest::OnPermissionChange,
152 base::Unretained(this))));
156 void RequestPermissionFromCurrentDocumentNonBlocking(
158 content::RenderFrameHost* rfh) {
159 GetPermissionManager()->RequestPermissionsFromCurrentDocument(
161 content::PermissionRequestDescription(
162 type, /*user_gesture=*/true,
163 rfh->GetLastCommittedOrigin().GetURL()),
165 [](base::OnceCallback<void(PermissionStatus)> callback,
166 const std::vector<PermissionStatus>& state) {
167 DCHECK_EQ(state.size(), 1U);
168 std::move(callback).Run(state[0]);
170 base::BindOnce(&PermissionManagerTest::OnPermissionChange,
171 base::Unretained(this))));
174 PermissionStatus GetPermissionStatusForCurrentDocument(
175 PermissionType permission,
176 content::RenderFrameHost* render_frame_host) {
177 return GetPermissionManager()->GetPermissionStatusForCurrentDocument(
178 permission, render_frame_host);
181 content::PermissionResult GetPermissionResultForCurrentDocument(
182 PermissionType permission,
183 content::RenderFrameHost* render_frame_host) {
184 return GetPermissionManager()->GetPermissionResultForCurrentDocument(
185 permission, render_frame_host);
188 PermissionStatus GetPermissionStatusForWorker(
189 PermissionType permission,
190 content::RenderProcessHost* render_process_host,
191 const GURL& worker_origin) {
192 return GetPermissionManager()->GetPermissionStatusForWorker(
193 permission, render_process_host, worker_origin);
196 content::PermissionControllerDelegate::SubscriptionId
197 SubscribePermissionStatusChange(
198 PermissionType permission,
199 content::RenderProcessHost* render_process_host,
200 content::RenderFrameHost* render_frame_host,
201 const GURL& requesting_origin,
202 base::RepeatingCallback<void(PermissionStatus)> callback) {
203 return GetPermissionManager()->SubscribePermissionStatusChange(
204 permission, render_process_host, render_frame_host, requesting_origin,
205 std::move(callback));
208 void UnsubscribePermissionStatusChange(
209 content::PermissionControllerDelegate::SubscriptionId subscription_id) {
210 GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
213 bool IsPermissionOverridable(PermissionType permission,
214 const absl::optional<url::Origin>& origin) {
215 return GetPermissionManager()->IsPermissionOverridable(permission, origin);
218 void ResetPermission(PermissionType permission,
219 const GURL& requesting_origin,
220 const GURL& embedding_origin) {
221 GetPermissionManager()->ResetPermission(permission, requesting_origin,
225 const GURL& url() const { return url_; }
227 const GURL& other_url() const { return other_url_; }
229 bool callback_called() const { return callback_called_; }
231 int callback_count() const { return callback_count_; }
233 PermissionStatus callback_result() const { return callback_result_; }
235 content::TestBrowserContext* browser_context() const {
236 return browser_context_.get();
240 callback_called_ = false;
242 callback_result_ = PermissionStatus::ASK;
245 bool PendingRequestsEmpty() {
246 return GetPermissionManager()->pending_requests_.IsEmpty();
249 // The header policy should only be set once on page load, so we refresh the
250 // page to simulate that.
251 void RefreshPageAndSetHeaderPolicy(content::RenderFrameHost** rfh,
252 PermissionsPolicyFeature feature,
253 const std::vector<std::string>& origins) {
254 content::RenderFrameHost* current = *rfh;
255 auto navigation = content::NavigationSimulator::CreateRendererInitiated(
256 current->GetLastCommittedURL(), current);
257 std::vector<blink::OriginWithPossibleWildcards> parsed_origins;
258 for (const std::string& origin : origins)
259 parsed_origins.emplace_back(
260 *blink::OriginWithPossibleWildcards::FromOrigin(
261 url::Origin::Create(GURL(origin))));
262 navigation->SetPermissionsPolicyHeader(
263 {{feature, parsed_origins, /*self_if_matches=*/absl::nullopt,
264 /*matches_all_origins=*/false,
265 /*matches_opaque_src=*/false}});
266 navigation->Commit();
267 *rfh = navigation->GetFinalRenderFrameHost();
270 content::RenderFrameHost* AddChildRFH(
271 content::RenderFrameHost* parent,
273 PermissionsPolicyFeature feature = PermissionsPolicyFeature::kNotFound) {
274 blink::ParsedPermissionsPolicy frame_policy = {};
275 if (feature != PermissionsPolicyFeature::kNotFound) {
276 frame_policy.emplace_back(
278 std::vector{*blink::OriginWithPossibleWildcards::FromOrigin(
279 url::Origin::Create(origin))},
280 /*self_if_matches=*/absl::nullopt,
281 /*matches_all_origins=*/false,
282 /*matches_opaque_src=*/false);
284 content::RenderFrameHost* result =
285 content::RenderFrameHostTester::For(parent)->AppendChildWithPolicy(
287 content::RenderFrameHostTester::For(result)
288 ->InitializeRenderFrameIfNeeded();
289 SimulateNavigation(&result, origin);
293 TestPermissionsClient& permissions_client() { return client_; }
296 void SetUp() override {
297 RenderViewHostTestHarness::SetUp();
298 browser_context_ = std::make_unique<content::TestBrowserContext>();
299 browser_context_->SetPermissionControllerDelegate(
300 permissions::GetPermissionControllerDelegate(browser_context_.get()));
301 NavigateAndCommit(url());
304 void TearDown() override {
305 GetPermissionManager()->Shutdown();
306 browser_context_ = nullptr;
307 RenderViewHostTestHarness::TearDown();
310 void SimulateNavigation(content::RenderFrameHost** rfh, const GURL& url) {
311 auto navigation_simulator =
312 content::NavigationSimulator::CreateRendererInitiated(url, *rfh);
313 navigation_simulator->Commit();
314 *rfh = navigation_simulator->GetFinalRenderFrameHost();
318 const GURL other_url_;
319 bool callback_called_ = false;
320 int callback_count_ = 0;
321 PermissionStatus callback_result_ = PermissionStatus::ASK;
322 base::OnceClosure quit_closure_;
323 std::unique_ptr<content::TestBrowserContext> browser_context_;
324 TestPermissionsClient client_;
327 TEST_F(PermissionManagerTest, GetPermissionStatusDefault) {
328 CheckPermissionStatus(PermissionType::MIDI_SYSEX, PermissionStatus::ASK);
329 CheckPermissionStatus(PermissionType::NOTIFICATIONS, PermissionStatus::ASK);
330 CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::ASK);
331 #if BUILDFLAG(IS_ANDROID)
332 CheckPermissionStatus(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
333 PermissionStatus::GRANTED);
334 CheckPermissionStatus(PermissionType::WINDOW_MANAGEMENT,
335 PermissionStatus::DENIED);
337 CheckPermissionStatus(PermissionType::WINDOW_MANAGEMENT,
338 PermissionStatus::ASK);
342 TEST_F(PermissionManagerTest, GetPermissionStatusAfterSet) {
343 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
344 CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
346 SetPermission(PermissionType::NOTIFICATIONS, PermissionStatus::GRANTED);
347 CheckPermissionStatus(PermissionType::NOTIFICATIONS,
348 PermissionStatus::GRANTED);
350 SetPermission(PermissionType::MIDI_SYSEX, PermissionStatus::GRANTED);
351 CheckPermissionStatus(PermissionType::MIDI_SYSEX, PermissionStatus::GRANTED);
353 #if BUILDFLAG(IS_ANDROID)
354 SetPermission(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
355 PermissionStatus::GRANTED);
356 CheckPermissionStatus(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
357 PermissionStatus::GRANTED);
359 SetPermission(PermissionType::WINDOW_MANAGEMENT, PermissionStatus::GRANTED);
360 CheckPermissionStatus(PermissionType::WINDOW_MANAGEMENT,
361 PermissionStatus::DENIED);
363 SetPermission(PermissionType::WINDOW_MANAGEMENT, PermissionStatus::GRANTED);
364 CheckPermissionStatus(PermissionType::WINDOW_MANAGEMENT,
365 PermissionStatus::GRANTED);
369 TEST_F(PermissionManagerTest, CheckPermissionResultDefault) {
370 CheckPermissionResult(PermissionType::MIDI_SYSEX, PermissionStatus::ASK,
371 content::PermissionStatusSource::UNSPECIFIED);
372 CheckPermissionResult(PermissionType::NOTIFICATIONS, PermissionStatus::ASK,
373 content::PermissionStatusSource::UNSPECIFIED);
374 CheckPermissionResult(PermissionType::GEOLOCATION, PermissionStatus::ASK,
375 content::PermissionStatusSource::UNSPECIFIED);
376 #if BUILDFLAG(IS_ANDROID)
377 CheckPermissionResult(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
378 PermissionStatus::GRANTED,
379 content::PermissionStatusSource::UNSPECIFIED);
383 TEST_F(PermissionManagerTest, CheckPermissionResultAfterSet) {
384 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
385 CheckPermissionResult(PermissionType::GEOLOCATION, PermissionStatus::GRANTED,
386 content::PermissionStatusSource::UNSPECIFIED);
388 SetPermission(PermissionType::NOTIFICATIONS, PermissionStatus::GRANTED);
389 CheckPermissionResult(PermissionType::NOTIFICATIONS,
390 PermissionStatus::GRANTED,
391 content::PermissionStatusSource::UNSPECIFIED);
393 SetPermission(PermissionType::MIDI_SYSEX, PermissionStatus::GRANTED);
394 CheckPermissionResult(PermissionType::MIDI_SYSEX, PermissionStatus::GRANTED,
395 content::PermissionStatusSource::UNSPECIFIED);
397 #if BUILDFLAG(IS_ANDROID)
398 SetPermission(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
399 PermissionStatus::GRANTED);
400 CheckPermissionResult(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
401 PermissionStatus::GRANTED,
402 content::PermissionStatusSource::UNSPECIFIED);
406 TEST_F(PermissionManagerTest, SubscriptionDestroyedCleanlyWithoutUnsubscribe) {
407 // Test that the PermissionManager shuts down cleanly with subscriptions that
408 // haven't been removed, crbug.com/720071.
409 SubscribePermissionStatusChange(
410 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr, main_rfh(),
412 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
413 base::Unretained(this)));
416 TEST_F(PermissionManagerTest, SubscribeUnsubscribeAfterShutdown) {
417 content::PermissionControllerDelegate::SubscriptionId subscription_id =
418 SubscribePermissionStatusChange(
419 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
421 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
422 base::Unretained(this)));
424 // Simulate Keyed Services shutdown pass. Note: Shutdown will be called second
425 // time during browser_context destruction. This is ok for now: Shutdown is
427 GetPermissionManager()->Shutdown();
429 UnsubscribePermissionStatusChange(subscription_id);
431 // Check that subscribe/unsubscribe after shutdown don't crash.
432 content::PermissionControllerDelegate::SubscriptionId subscription2_id =
433 SubscribePermissionStatusChange(
434 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
436 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
437 base::Unretained(this)));
439 UnsubscribePermissionStatusChange(subscription2_id);
442 TEST_F(PermissionManagerTest, SameTypeChangeNotifies) {
443 content::PermissionControllerDelegate::SubscriptionId subscription_id =
444 SubscribePermissionStatusChange(
445 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
447 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
448 base::Unretained(this)));
450 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
452 EXPECT_TRUE(callback_called());
453 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
455 UnsubscribePermissionStatusChange(subscription_id);
458 TEST_F(PermissionManagerTest, DifferentTypeChangeDoesNotNotify) {
459 content::PermissionControllerDelegate::SubscriptionId subscription_id =
460 SubscribePermissionStatusChange(
461 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
463 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
464 base::Unretained(this)));
466 SetPermission(url(), GURL(), PermissionType::NOTIFICATIONS,
467 PermissionStatus::GRANTED);
469 EXPECT_FALSE(callback_called());
471 UnsubscribePermissionStatusChange(subscription_id);
474 TEST_F(PermissionManagerTest, ChangeAfterUnsubscribeDoesNotNotify) {
475 content::PermissionControllerDelegate::SubscriptionId subscription_id =
476 SubscribePermissionStatusChange(
477 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
479 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
480 base::Unretained(this)));
482 UnsubscribePermissionStatusChange(subscription_id);
484 SetPermission(url(), url(), PermissionType::GEOLOCATION,
485 PermissionStatus::GRANTED);
487 EXPECT_FALSE(callback_called());
490 TEST_F(PermissionManagerTest,
491 ChangeAfterUnsubscribeOnlyNotifiesActiveSubscribers) {
492 content::PermissionControllerDelegate::SubscriptionId subscription_id =
493 SubscribePermissionStatusChange(
494 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
496 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
497 base::Unretained(this)));
499 SubscribePermissionStatusChange(
500 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr, main_rfh(),
502 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
503 base::Unretained(this)));
505 UnsubscribePermissionStatusChange(subscription_id);
507 SetPermission(url(), url(), PermissionType::GEOLOCATION,
508 PermissionStatus::GRANTED);
510 EXPECT_EQ(callback_count(), 1);
513 TEST_F(PermissionManagerTest, DifferentPrimaryUrlDoesNotNotify) {
514 content::PermissionControllerDelegate::SubscriptionId subscription_id =
515 SubscribePermissionStatusChange(
516 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
518 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
519 base::Unretained(this)));
521 SetPermission(other_url(), url(), PermissionType::GEOLOCATION,
522 PermissionStatus::GRANTED);
524 EXPECT_FALSE(callback_called());
526 UnsubscribePermissionStatusChange(subscription_id);
529 TEST_F(PermissionManagerTest, DifferentSecondaryUrlDoesNotNotify) {
530 content::PermissionControllerDelegate::SubscriptionId subscription_id =
531 SubscribePermissionStatusChange(
532 PermissionType::STORAGE_ACCESS_GRANT, /*render_process_host=*/nullptr,
534 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
535 base::Unretained(this)));
537 SetPermission(url(), other_url(), PermissionType::STORAGE_ACCESS_GRANT,
538 PermissionStatus::GRANTED);
540 EXPECT_FALSE(callback_called());
542 UnsubscribePermissionStatusChange(subscription_id);
545 TEST_F(PermissionManagerTest, WildCardPatternNotifies) {
546 content::PermissionControllerDelegate::SubscriptionId subscription_id =
547 SubscribePermissionStatusChange(
548 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
550 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
551 base::Unretained(this)));
553 GetHostContentSettingsMap()->SetDefaultContentSetting(
554 ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
556 EXPECT_TRUE(callback_called());
557 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
559 UnsubscribePermissionStatusChange(subscription_id);
562 TEST_F(PermissionManagerTest, ClearSettingsNotifies) {
563 SetPermission(url(), url(), PermissionType::GEOLOCATION,
564 PermissionStatus::GRANTED);
566 content::PermissionControllerDelegate::SubscriptionId subscription_id =
567 SubscribePermissionStatusChange(
568 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
570 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
571 base::Unretained(this)));
573 GetHostContentSettingsMap()->ClearSettingsForOneType(
574 ContentSettingsType::GEOLOCATION);
576 EXPECT_TRUE(callback_called());
577 EXPECT_EQ(PermissionStatus::ASK, callback_result());
579 UnsubscribePermissionStatusChange(subscription_id);
582 TEST_F(PermissionManagerTest, NewValueCorrectlyPassed) {
583 content::PermissionControllerDelegate::SubscriptionId subscription_id =
584 SubscribePermissionStatusChange(
585 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
587 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
588 base::Unretained(this)));
590 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::DENIED);
592 EXPECT_TRUE(callback_called());
593 EXPECT_EQ(PermissionStatus::DENIED, callback_result());
595 UnsubscribePermissionStatusChange(subscription_id);
598 TEST_F(PermissionManagerTest, ChangeWithoutPermissionChangeDoesNotNotify) {
599 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
601 content::PermissionControllerDelegate::SubscriptionId subscription_id =
602 SubscribePermissionStatusChange(
603 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
605 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
606 base::Unretained(this)));
608 SetPermission(url(), url(), PermissionType::GEOLOCATION,
609 PermissionStatus::GRANTED);
611 EXPECT_FALSE(callback_called());
613 UnsubscribePermissionStatusChange(subscription_id);
616 TEST_F(PermissionManagerTest, ChangesBackAndForth) {
617 SetPermission(url(), url(), PermissionType::GEOLOCATION,
618 PermissionStatus::ASK);
620 content::PermissionControllerDelegate::SubscriptionId subscription_id =
621 SubscribePermissionStatusChange(
622 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
624 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
625 base::Unretained(this)));
627 SetPermission(url(), url(), PermissionType::GEOLOCATION,
628 PermissionStatus::GRANTED);
630 EXPECT_TRUE(callback_called());
631 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
635 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::ASK);
637 EXPECT_TRUE(callback_called());
638 EXPECT_EQ(PermissionStatus::ASK, callback_result());
640 UnsubscribePermissionStatusChange(subscription_id);
643 TEST_F(PermissionManagerTest, ChangesBackAndForthWorker) {
644 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::ASK);
646 content::PermissionControllerDelegate::SubscriptionId subscription_id =
647 SubscribePermissionStatusChange(
648 PermissionType::GEOLOCATION, process(), /*render_frame_host=*/nullptr,
650 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
651 base::Unretained(this)));
653 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
655 EXPECT_TRUE(callback_called());
656 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
660 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::ASK);
662 EXPECT_TRUE(callback_called());
663 EXPECT_EQ(PermissionStatus::ASK, callback_result());
665 UnsubscribePermissionStatusChange(subscription_id);
668 TEST_F(PermissionManagerTest, SubscribeMIDIPermission) {
669 content::PermissionControllerDelegate::SubscriptionId subscription_id =
670 SubscribePermissionStatusChange(
671 PermissionType::MIDI, /*render_process_host=*/nullptr, main_rfh(),
673 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
674 base::Unretained(this)));
676 CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::ASK);
677 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
678 CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
680 EXPECT_FALSE(callback_called());
682 UnsubscribePermissionStatusChange(subscription_id);
685 TEST_F(PermissionManagerTest, PermissionIgnoredCleanup) {
686 content::WebContents* contents = web_contents();
687 PermissionRequestManager::CreateForWebContents(contents);
688 PermissionRequestManager* manager =
689 PermissionRequestManager::FromWebContents(contents);
690 auto prompt_factory = std::make_unique<MockPermissionPromptFactory>(manager);
692 NavigateAndCommit(url());
694 RequestPermissionFromCurrentDocumentNonBlocking(PermissionType::GEOLOCATION,
697 EXPECT_FALSE(PendingRequestsEmpty());
699 NavigateAndCommit(GURL("https://foobar.com"));
701 EXPECT_TRUE(callback_called());
702 EXPECT_TRUE(PendingRequestsEmpty());
705 // Check PermissionResult shows requests denied due to insecure
707 TEST_F(PermissionManagerTest, InsecureOrigin) {
708 GURL insecure_frame("http://www.example.com/geolocation");
709 NavigateAndCommit(insecure_frame);
711 content::PermissionResult result = GetPermissionResultForCurrentDocument(
712 PermissionType::GEOLOCATION, web_contents()->GetPrimaryMainFrame());
714 EXPECT_EQ(PermissionStatus::DENIED, result.status);
715 EXPECT_EQ(content::PermissionStatusSource::INSECURE_ORIGIN, result.source);
717 GURL secure_frame("https://www.example.com/geolocation");
718 NavigateAndCommit(secure_frame);
720 result = GetPermissionResultForCurrentDocument(
721 PermissionType::GEOLOCATION, web_contents()->GetPrimaryMainFrame());
723 EXPECT_EQ(PermissionStatus::ASK, result.status);
724 EXPECT_EQ(content::PermissionStatusSource::UNSPECIFIED, result.source);
727 TEST_F(PermissionManagerTest, InsecureOriginIsNotOverridable) {
728 const url::Origin kInsecureOrigin =
729 url::Origin::Create(GURL("http://example.com/geolocation"));
730 const url::Origin kSecureOrigin =
731 url::Origin::Create(GURL("https://example.com/geolocation"));
733 IsPermissionOverridable(PermissionType::GEOLOCATION, kInsecureOrigin));
735 IsPermissionOverridable(PermissionType::GEOLOCATION, kSecureOrigin));
738 TEST_F(PermissionManagerTest, MissingContextIsNotOverridable) {
739 // Permissions that are not implemented should be denied overridability.
740 #if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
742 IsPermissionOverridable(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
743 url::Origin::Create(GURL("http://localhost"))));
746 IsPermissionOverridable(PermissionType::MIDI_SYSEX,
747 url::Origin::Create(GURL("http://localhost"))));
750 TEST_F(PermissionManagerTest, KillSwitchOnIsNotOverridable) {
751 const url::Origin kLocalHost = url::Origin::Create(GURL("http://localhost"));
752 EXPECT_TRUE(IsPermissionOverridable(PermissionType::GEOLOCATION, kLocalHost));
754 // Turn on kill switch for GEOLOCATION.
755 std::map<std::string, std::string> params;
756 params[PermissionUtil::GetPermissionString(
757 ContentSettingsType::GEOLOCATION)] =
758 PermissionContextBase::kPermissionsKillSwitchBlockedValue;
759 base::AssociateFieldTrialParams(
760 PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup",
762 base::FieldTrialList::CreateFieldTrial(
763 PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup");
766 IsPermissionOverridable(PermissionType::GEOLOCATION, kLocalHost));
769 TEST_F(PermissionManagerTest, ResetPermission) {
770 #if BUILDFLAG(IS_ANDROID)
771 CheckPermissionStatus(PermissionType::NOTIFICATIONS, PermissionStatus::ASK);
772 SetPermission(PermissionType::NOTIFICATIONS, PermissionStatus::GRANTED);
773 CheckPermissionStatus(PermissionType::NOTIFICATIONS,
774 PermissionStatus::GRANTED);
776 ResetPermission(PermissionType::NOTIFICATIONS, url(), url());
778 CheckPermissionStatus(PermissionType::NOTIFICATIONS, PermissionStatus::ASK);
780 const char* kOrigin1 = "https://example.com";
782 NavigateAndCommit(GURL(kOrigin1));
783 content::RenderFrameHost* rfh = main_rfh();
785 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
786 PermissionType::NOTIFICATIONS, rfh));
788 PermissionRequestManager::CreateForWebContents(web_contents());
789 PermissionRequestManager* manager =
790 PermissionRequestManager::FromWebContents(web_contents());
791 auto prompt_factory = std::make_unique<MockPermissionPromptFactory>(manager);
792 prompt_factory->set_response_type(PermissionRequestManager::ACCEPT_ALL);
793 prompt_factory->DocumentOnLoadCompletedInPrimaryMainFrame();
795 RequestPermissionFromCurrentDocument(PermissionType::NOTIFICATIONS, rfh);
797 EXPECT_EQ(PermissionStatus::GRANTED, GetPermissionStatusForCurrentDocument(
798 PermissionType::NOTIFICATIONS, rfh));
800 ResetPermission(PermissionType::NOTIFICATIONS, GURL(kOrigin1),
803 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
804 PermissionType::NOTIFICATIONS, rfh));
808 TEST_F(PermissionManagerTest, GetPermissionStatusDelegation) {
809 const char* kOrigin1 = "https://example.com";
810 const char* kOrigin2 = "https://google.com";
812 NavigateAndCommit(GURL(kOrigin1));
813 content::RenderFrameHost* parent = main_rfh();
815 content::RenderFrameHost* child = AddChildRFH(parent, GURL(kOrigin2));
817 // By default the parent should be able to request access, but not the child.
818 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
819 PermissionType::GEOLOCATION, parent));
820 EXPECT_EQ(PermissionStatus::DENIED, GetPermissionStatusForCurrentDocument(
821 PermissionType::GEOLOCATION, child));
823 // Enabling geolocation by FP should allow the child to request access also.
824 child = AddChildRFH(parent, GURL(kOrigin2),
825 PermissionsPolicyFeature::kGeolocation);
827 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
828 PermissionType::GEOLOCATION, child));
830 // When the child requests location a prompt should be displayed for the
832 PermissionRequestManager::CreateForWebContents(web_contents());
833 PermissionRequestManager* manager =
834 PermissionRequestManager::FromWebContents(web_contents());
835 auto prompt_factory = std::make_unique<MockPermissionPromptFactory>(manager);
836 prompt_factory->set_response_type(PermissionRequestManager::ACCEPT_ALL);
837 prompt_factory->DocumentOnLoadCompletedInPrimaryMainFrame();
839 RequestPermissionFromCurrentDocument(PermissionType::GEOLOCATION, child);
841 EXPECT_TRUE(prompt_factory->RequestOriginSeen(GURL(kOrigin1)));
843 // Now the child frame should have location, as well as the parent frame.
844 EXPECT_EQ(PermissionStatus::GRANTED,
845 GetPermissionStatusForCurrentDocument(PermissionType::GEOLOCATION,
847 EXPECT_EQ(PermissionStatus::GRANTED, GetPermissionStatusForCurrentDocument(
848 PermissionType::GEOLOCATION, child));
850 // Revoking access from the parent should cause the child not to have access
852 ResetPermission(PermissionType::GEOLOCATION, GURL(kOrigin1), GURL(kOrigin1));
853 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
854 PermissionType::GEOLOCATION, parent));
855 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
856 PermissionType::GEOLOCATION, child));
858 // If the parent changes its policy, the child should be blocked.
859 RefreshPageAndSetHeaderPolicy(&parent, PermissionsPolicyFeature::kGeolocation,
861 child = AddChildRFH(parent, GURL(kOrigin2));
863 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
864 PermissionType::GEOLOCATION, parent));
865 EXPECT_EQ(PermissionStatus::DENIED, GetPermissionStatusForCurrentDocument(
866 PermissionType::GEOLOCATION, child));
868 prompt_factory.reset();
871 TEST_F(PermissionManagerTest, SubscribeWithPermissionDelegation) {
872 const char* kOrigin1 = "https://example.com";
873 const char* kOrigin2 = "https://google.com";
875 NavigateAndCommit(GURL(kOrigin1));
876 content::RenderFrameHost* parent = main_rfh();
877 content::RenderFrameHost* child = AddChildRFH(parent, GURL(kOrigin2));
879 content::PermissionControllerDelegate::SubscriptionId subscription_id =
880 SubscribePermissionStatusChange(
881 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr, child,
883 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
884 base::Unretained(this)));
885 EXPECT_FALSE(callback_called());
887 // Location should be blocked for the child because it's not delegated.
888 EXPECT_EQ(PermissionStatus::DENIED, GetPermissionStatusForCurrentDocument(
889 PermissionType::GEOLOCATION, child));
891 // Allow access for the top level origin.
892 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
894 // The child's permission should still be block and no callback should be run.
895 EXPECT_EQ(PermissionStatus::DENIED, GetPermissionStatusForCurrentDocument(
896 PermissionType::GEOLOCATION, child));
898 EXPECT_FALSE(callback_called());
900 // Enabling geolocation by FP should allow the child to request access also.
901 child = AddChildRFH(parent, GURL(kOrigin2),
902 PermissionsPolicyFeature::kGeolocation);
904 EXPECT_EQ(PermissionStatus::GRANTED, GetPermissionStatusForCurrentDocument(
905 PermissionType::GEOLOCATION, child));
907 subscription_id = SubscribePermissionStatusChange(
908 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr, child,
910 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
911 base::Unretained(this)));
912 EXPECT_FALSE(callback_called());
914 // Blocking access to the parent should trigger the callback to be run for the
916 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::DENIED);
918 EXPECT_TRUE(callback_called());
919 EXPECT_EQ(PermissionStatus::DENIED, callback_result());
921 EXPECT_EQ(PermissionStatus::DENIED, GetPermissionStatusForCurrentDocument(
922 PermissionType::GEOLOCATION, child));
924 UnsubscribePermissionStatusChange(subscription_id);
927 TEST_F(PermissionManagerTest, SubscribeUnsubscribeAndResubscribe) {
928 const char* kOrigin1 = "https://example.com";
929 NavigateAndCommit(GURL(kOrigin1));
931 content::PermissionControllerDelegate::SubscriptionId subscription_id =
932 SubscribePermissionStatusChange(
933 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
934 main_rfh(), GURL(kOrigin1),
935 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
936 base::Unretained(this)));
937 EXPECT_EQ(callback_count(), 0);
939 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
941 EXPECT_EQ(callback_count(), 1);
942 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
944 UnsubscribePermissionStatusChange(subscription_id);
946 // ensure no callbacks are received when unsubscribed.
947 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::DENIED);
948 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
950 EXPECT_EQ(callback_count(), 1);
952 content::PermissionControllerDelegate::SubscriptionId subscription_id_2 =
953 SubscribePermissionStatusChange(
954 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
955 main_rfh(), GURL(kOrigin1),
956 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
957 base::Unretained(this)));
958 EXPECT_EQ(callback_count(), 1);
960 SetPermission(PermissionType::GEOLOCATION, PermissionStatus::DENIED);
962 EXPECT_EQ(callback_count(), 2);
963 EXPECT_EQ(PermissionStatus::DENIED, callback_result());
965 UnsubscribePermissionStatusChange(subscription_id_2);
968 TEST_F(PermissionManagerTest, GetCanonicalOrigin) {
969 GURL requesting("https://requesting.example.com");
970 GURL embedding("https://embedding.example.com");
973 permissions::PermissionUtil::GetCanonicalOrigin(
974 ContentSettingsType::COOKIES, requesting, embedding));
975 EXPECT_EQ(requesting,
976 permissions::PermissionUtil::GetCanonicalOrigin(
977 ContentSettingsType::NOTIFICATIONS, requesting, embedding));
978 EXPECT_EQ(requesting,
979 permissions::PermissionUtil::GetCanonicalOrigin(
980 ContentSettingsType::STORAGE_ACCESS, requesting, embedding));
983 TEST_F(PermissionManagerTest, RequestPermissionInDifferentStoragePartition) {
984 const GURL kOrigin("https://example.com");
985 const GURL kOrigin2("https://example2.com");
986 const GURL kPartitionedOrigin("https://partitioned.com");
987 ScopedPartitionedOriginBrowserClient browser_client(kPartitionedOrigin);
989 SetPermission(kOrigin, PermissionType::GEOLOCATION,
990 PermissionStatus::GRANTED);
992 SetPermission(kOrigin2, PermissionType::GEOLOCATION,
993 PermissionStatus::DENIED);
994 SetPermission(kOrigin2, PermissionType::NOTIFICATIONS,
995 PermissionStatus::GRANTED);
997 SetPermission(kPartitionedOrigin, PermissionType::GEOLOCATION,
998 PermissionStatus::DENIED);
999 SetPermission(kPartitionedOrigin, PermissionType::NOTIFICATIONS,
1000 PermissionStatus::GRANTED);
1002 NavigateAndCommit(kOrigin);
1003 content::RenderFrameHost* parent = main_rfh();
1005 content::RenderFrameHost* child =
1006 AddChildRFH(parent, kOrigin2, PermissionsPolicyFeature::kGeolocation);
1007 content::RenderFrameHost* partitioned_child = AddChildRFH(
1008 parent, kPartitionedOrigin, PermissionsPolicyFeature::kGeolocation);
1010 // The parent should have geolocation access which is delegated to child and
1011 // partitioned_child.
1012 EXPECT_EQ(PermissionStatus::GRANTED,
1013 GetPermissionStatusForCurrentDocument(PermissionType::GEOLOCATION,
1015 EXPECT_EQ(PermissionStatus::GRANTED, GetPermissionStatusForCurrentDocument(
1016 PermissionType::GEOLOCATION, child));
1017 EXPECT_EQ(PermissionStatus::GRANTED,
1018 GetPermissionStatusForCurrentDocument(PermissionType::GEOLOCATION,
1019 partitioned_child));
1021 // The parent should not have notification permission.
1022 EXPECT_EQ(PermissionStatus::ASK, GetPermissionStatusForCurrentDocument(
1023 PermissionType::NOTIFICATIONS, parent));
1024 EXPECT_EQ(PermissionStatus::ASK,
1025 GetPermissionStatusForWorker(
1026 PermissionType::NOTIFICATIONS, parent->GetProcess(),
1027 parent->GetLastCommittedOrigin().GetURL()));
1029 // The non-partitioned child should have notification permission.
1030 EXPECT_EQ(PermissionStatus::GRANTED,
1031 GetPermissionStatusForCurrentDocument(PermissionType::NOTIFICATIONS,
1033 EXPECT_EQ(PermissionStatus::GRANTED,
1034 GetPermissionStatusForWorker(
1035 PermissionType::NOTIFICATIONS, child->GetProcess(),
1036 child->GetLastCommittedOrigin().GetURL()));
1038 // The partitioned child should not have notification permission because it
1039 // belongs to a different StoragePartition, even though its origin would have
1040 // permission if loaded in a main frame.
1041 EXPECT_EQ(PermissionStatus::DENIED,
1042 GetPermissionStatusForCurrentDocument(PermissionType::NOTIFICATIONS,
1043 partitioned_child));
1044 EXPECT_EQ(PermissionStatus::DENIED,
1045 GetPermissionStatusForWorker(
1046 PermissionType::NOTIFICATIONS, partitioned_child->GetProcess(),
1047 partitioned_child->GetLastCommittedOrigin().GetURL()));
1050 TEST_F(PermissionManagerTest, SubscribersAreNotifedOfEmbargoEvents) {
1051 const char* kOrigin1 = "https://example.com";
1052 NavigateAndCommit(GURL(kOrigin1));
1054 content::PermissionControllerDelegate::SubscriptionId subscription_id =
1055 SubscribePermissionStatusChange(
1056 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
1057 main_rfh(), GURL(kOrigin1),
1058 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
1059 base::Unretained(this)));
1060 EXPECT_EQ(callback_count(), 0);
1063 permissions::PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
1066 // 3 dismisses will trigger embargo, which should call the subscription
1068 autoblocker->RecordDismissAndEmbargo(GURL(kOrigin1),
1069 ContentSettingsType::GEOLOCATION,
1070 false /* dismissed_prompt_was_quiet */);
1071 EXPECT_EQ(callback_count(), 0);
1072 autoblocker->RecordDismissAndEmbargo(GURL(kOrigin1),
1073 ContentSettingsType::GEOLOCATION,
1074 false /* dismissed_prompt_was_quiet */);
1075 EXPECT_EQ(callback_count(), 0);
1076 autoblocker->RecordDismissAndEmbargo(GURL(kOrigin1),
1077 ContentSettingsType::GEOLOCATION,
1078 false /* dismissed_prompt_was_quiet */);
1079 EXPECT_EQ(callback_count(), 1);
1081 UnsubscribePermissionStatusChange(subscription_id);
1084 TEST_F(PermissionManagerTest, UpdatePermissionStatusWithDeviceStatus) {
1086 blink::mojom::PermissionStatus initial_status;
1087 bool has_device_permission;
1088 bool can_request_device_permission;
1089 blink::mojom::PermissionStatus expected_status =
1090 initial_status; // For most of these test cases the expected status is
1091 // the same as the initial status
1093 {blink::mojom::PermissionStatus::GRANTED, false, false,
1094 blink::mojom::PermissionStatus::DENIED},
1095 {blink::mojom::PermissionStatus::GRANTED, false, true,
1096 blink::mojom::PermissionStatus::ASK},
1097 {blink::mojom::PermissionStatus::GRANTED, true, false},
1098 {blink::mojom::PermissionStatus::GRANTED, true, true},
1100 {blink::mojom::PermissionStatus::ASK, false, false},
1101 {blink::mojom::PermissionStatus::ASK, false, true},
1102 {blink::mojom::PermissionStatus::ASK, true, false},
1103 {blink::mojom::PermissionStatus::ASK, true, true},
1105 {blink::mojom::PermissionStatus::DENIED, false, false},
1106 {blink::mojom::PermissionStatus::DENIED, false, true},
1107 {blink::mojom::PermissionStatus::DENIED, true, false},
1108 {blink::mojom::PermissionStatus::DENIED, true, true},
1111 GURL url("http://google.com");
1113 for (const auto& test : kTests) {
1114 SCOPED_TRACE(::testing::Message()
1115 << "initial_status:" << test.initial_status
1116 << ", expected_status: " << test.expected_status
1117 << ", has_device_permission: " << test.has_device_permission
1118 << ", can_request_device_permission: "
1119 << test.can_request_device_permission);
1121 SetPermission(blink::PermissionType::NOTIFICATIONS, test.initial_status);
1122 permissions_client().SetHasDevicePermission(test.has_device_permission);
1123 permissions_client().SetCanRequestDevicePermission(
1124 test.can_request_device_permission);
1126 CheckPermissionStatus(blink::PermissionType::NOTIFICATIONS,
1127 test.expected_status);
1131 TEST_F(PermissionManagerTest,
1132 RequestableDevicePermissionChangesLazilyNotifiesObservers) {
1133 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1134 PermissionStatus::GRANTED);
1135 permissions_client().SetHasDevicePermission(true);
1136 permissions_client().SetCanRequestDevicePermission(true);
1138 content::PermissionControllerDelegate::SubscriptionId subscription_id =
1139 SubscribePermissionStatusChange(
1140 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
1142 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
1143 base::Unretained(this)));
1145 permissions_client().SetHasDevicePermission(false);
1147 // At this point we have not yet retrieved the permission status so the device
1148 // permission change has not been detected.
1149 EXPECT_FALSE(callback_called());
1151 // This call will trigger an update of the device permission status and
1152 // observers will be notified if needed.
1153 GetPermissionResultForCurrentDocument(PermissionType::GEOLOCATION,
1154 web_contents()->GetPrimaryMainFrame());
1156 EXPECT_TRUE(callback_called());
1157 EXPECT_EQ(PermissionStatus::ASK, callback_result());
1160 // This does not change the overall permission status so no callback should be
1162 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1163 PermissionStatus::ASK);
1164 EXPECT_FALSE(callback_called());
1166 // This does change the overall permission status from ask to blocked.
1167 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1168 PermissionStatus::DENIED);
1169 EXPECT_TRUE(callback_called());
1170 EXPECT_EQ(PermissionStatus::DENIED, callback_result());
1173 // We now reset to a granted state, which should move the overall permission
1174 // status to ask (origin status "granted", but Chrome does not have the device
1176 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1177 PermissionStatus::GRANTED);
1178 EXPECT_TRUE(callback_called());
1179 EXPECT_EQ(PermissionStatus::ASK, callback_result());
1182 // Now we reset the device permission status back to granted, which moves the
1183 // overall permission status to granted.
1184 permissions_client().SetHasDevicePermission(true);
1186 // At this point we have not yet refreshed the permission status.
1187 EXPECT_FALSE(callback_called());
1189 // This call will make us retrieve the device permission status and observers
1190 // will be notified if needed.
1191 GetPermissionResultForCurrentDocument(PermissionType::GEOLOCATION,
1192 web_contents()->GetPrimaryMainFrame());
1194 EXPECT_TRUE(callback_called());
1195 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
1197 UnsubscribePermissionStatusChange(subscription_id);
1200 TEST_F(PermissionManagerTest,
1201 NonrequestableDevicePermissionChangesLazilyNotifiesObservers) {
1202 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1203 PermissionStatus::GRANTED);
1204 permissions_client().SetHasDevicePermission(true);
1205 permissions_client().SetCanRequestDevicePermission(false);
1207 content::PermissionControllerDelegate::SubscriptionId subscription_id =
1208 SubscribePermissionStatusChange(
1209 PermissionType::GEOLOCATION, /*render_process_host=*/nullptr,
1211 base::BindRepeating(&PermissionManagerTest::OnPermissionChange,
1212 base::Unretained(this)));
1215 GetPermissionResultForCurrentDocument(
1216 PermissionType::GEOLOCATION, web_contents()->GetPrimaryMainFrame())
1218 blink::mojom::PermissionStatus::GRANTED);
1220 permissions_client().SetHasDevicePermission(false);
1222 // At this point the device permission has not been queried yet.
1223 EXPECT_FALSE(callback_called());
1225 // Get permission status to also trigger the device permission being queried
1226 // which would result in observers being notified.
1227 GetPermissionResultForCurrentDocument(PermissionType::GEOLOCATION,
1228 web_contents()->GetPrimaryMainFrame());
1230 EXPECT_TRUE(callback_called());
1231 EXPECT_EQ(PermissionStatus::DENIED, callback_result());
1234 // Overall these 2 changes don't change the permission status, since the
1235 // status moves back to "denied". While there is a brief moment when both
1236 // device and origin-level permissions are granted, the device permission
1237 // status is not queried in the mean time so observers won't be notified.
1238 permissions_client().SetHasDevicePermission(true);
1239 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1240 PermissionStatus::DENIED);
1242 EXPECT_FALSE(callback_called());
1244 SetPermission(url(), url(), PermissionType::GEOLOCATION,
1245 PermissionStatus::GRANTED);
1246 EXPECT_TRUE(callback_called());
1247 EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
1250 UnsubscribePermissionStatusChange(subscription_id);
1253 } // namespace permissions