1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/command_line.h"
10 #include "base/run_loop.h"
11 #include "base/test/metrics/histogram_tester.h"
12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "build/build_config.h"
14 #include "components/permissions/notification_permission_ui_selector.h"
15 #include "components/permissions/permission_request.h"
16 #include "components/permissions/permission_request_manager.h"
17 #include "components/permissions/permission_uma_util.h"
18 #include "components/permissions/test/mock_permission_prompt_factory.h"
19 #include "components/permissions/test/mock_permission_request.h"
20 #include "components/permissions/test/test_permissions_client.h"
21 #include "content/public/test/test_renderer_host.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace permissions {
27 using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
30 class PermissionRequestManagerTest : public content::RenderViewHostTestHarness {
32 PermissionRequestManagerTest()
33 : content::RenderViewHostTestHarness(),
35 PermissionRequestType::QUOTA,
36 PermissionRequestGestureType::GESTURE),
38 PermissionRequestType::DOWNLOAD,
39 PermissionRequestGestureType::NO_GESTURE),
41 PermissionRequestType::PERMISSION_MEDIASTREAM_MIC,
42 PermissionRequestGestureType::NO_GESTURE),
43 request_camera_("cam",
44 PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA,
45 PermissionRequestGestureType::NO_GESTURE),
47 PermissionRequestType::PERMISSION_CAMERA_PAN_TILT_ZOOM,
48 PermissionRequestGestureType::NO_GESTURE),
49 iframe_request_same_domain_(
51 PermissionRequestType::PERMISSION_NOTIFICATIONS,
52 GURL("http://www.google.com/some/url")),
53 iframe_request_other_domain_(
55 PermissionRequestType::PERMISSION_GEOLOCATION,
56 GURL("http://www.youtube.com")),
57 iframe_request_camera_other_domain_(
59 PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA,
60 GURL("http://www.youtube.com")),
61 iframe_request_mic_other_domain_(
63 PermissionRequestType::PERMISSION_MEDIASTREAM_MIC,
64 GURL("http://www.youtube.com")) {}
66 void SetUp() override {
67 content::RenderViewHostTestHarness::SetUp();
68 SetContents(CreateTestWebContents());
69 url_ = GURL("http://www.google.com");
70 NavigateAndCommit(url_);
72 PermissionRequestManager::CreateForWebContents(web_contents());
73 manager_ = PermissionRequestManager::FromWebContents(web_contents());
74 prompt_factory_ = std::make_unique<MockPermissionPromptFactory>(manager_);
77 void TearDown() override {
78 prompt_factory_ = nullptr;
79 content::RenderViewHostTestHarness::TearDown();
84 base::RunLoop().RunUntilIdle();
89 base::RunLoop().RunUntilIdle();
94 base::RunLoop().RunUntilIdle();
97 void WaitForFrameLoad() {
98 // PermissionRequestManager ignores all parameters. Yay?
99 manager_->DOMContentLoaded(nullptr);
100 base::RunLoop().RunUntilIdle();
103 void WaitForBubbleToBeShown() {
104 manager_->DocumentOnLoadCompletedInMainFrame();
105 base::RunLoop().RunUntilIdle();
108 void MockTabSwitchAway() {
109 manager_->OnVisibilityChanged(content::Visibility::HIDDEN);
112 void MockTabSwitchBack() {
113 manager_->OnVisibilityChanged(content::Visibility::VISIBLE);
116 virtual void NavigationEntryCommitted(
117 const content::LoadCommittedDetails& details) {
118 manager_->NavigationEntryCommitted(details);
123 MockPermissionRequest request1_;
124 MockPermissionRequest request2_;
125 MockPermissionRequest request_mic_;
126 MockPermissionRequest request_camera_;
127 MockPermissionRequest request_ptz_;
128 MockPermissionRequest iframe_request_same_domain_;
129 MockPermissionRequest iframe_request_other_domain_;
130 MockPermissionRequest iframe_request_camera_other_domain_;
131 MockPermissionRequest iframe_request_mic_other_domain_;
132 PermissionRequestManager* manager_;
133 std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
134 TestPermissionsClient client_;
137 TEST_F(PermissionRequestManagerTest, SingleRequest) {
138 manager_->AddRequest(&request1_);
139 WaitForBubbleToBeShown();
141 EXPECT_TRUE(prompt_factory_->is_visible());
142 ASSERT_EQ(prompt_factory_->request_count(), 1);
145 EXPECT_TRUE(request1_.granted());
148 TEST_F(PermissionRequestManagerTest, SingleRequestViewFirst) {
149 manager_->AddRequest(&request1_);
150 WaitForBubbleToBeShown();
152 EXPECT_TRUE(prompt_factory_->is_visible());
153 ASSERT_EQ(prompt_factory_->request_count(), 1);
156 EXPECT_TRUE(request1_.granted());
159 // Most requests should never be grouped.
160 TEST_F(PermissionRequestManagerTest, TwoRequestsUngrouped) {
161 manager_->AddRequest(&request1_);
162 manager_->AddRequest(&request2_);
164 WaitForBubbleToBeShown();
165 EXPECT_TRUE(prompt_factory_->is_visible());
166 ASSERT_EQ(prompt_factory_->request_count(), 1);
168 EXPECT_TRUE(request1_.granted());
170 WaitForBubbleToBeShown();
171 EXPECT_TRUE(prompt_factory_->is_visible());
172 ASSERT_EQ(prompt_factory_->request_count(), 1);
174 EXPECT_TRUE(request2_.granted());
177 // Only mic/camera requests from the same origin should be grouped.
178 TEST_F(PermissionRequestManagerTest, MicCameraGrouped) {
179 manager_->AddRequest(&request_mic_);
180 manager_->AddRequest(&request_camera_);
181 WaitForBubbleToBeShown();
183 EXPECT_TRUE(prompt_factory_->is_visible());
184 ASSERT_EQ(prompt_factory_->request_count(), 2);
187 EXPECT_TRUE(request_mic_.granted());
188 EXPECT_TRUE(request_camera_.granted());
190 // If the requests come from different origins, they should not be grouped.
191 manager_->AddRequest(&iframe_request_mic_other_domain_);
192 manager_->AddRequest(&request_camera_);
193 WaitForBubbleToBeShown();
195 EXPECT_TRUE(prompt_factory_->is_visible());
196 ASSERT_EQ(prompt_factory_->request_count(), 1);
199 // Only camera/ptz requests from the same origin should be grouped.
200 TEST_F(PermissionRequestManagerTest, CameraPtzGrouped) {
201 manager_->AddRequest(&request_camera_);
202 manager_->AddRequest(&request_ptz_);
203 WaitForBubbleToBeShown();
205 EXPECT_TRUE(prompt_factory_->is_visible());
206 ASSERT_EQ(prompt_factory_->request_count(), 2);
209 EXPECT_TRUE(request_camera_.granted());
210 EXPECT_TRUE(request_ptz_.granted());
212 // If the requests come from different origins, they should not be grouped.
213 manager_->AddRequest(&iframe_request_camera_other_domain_);
214 manager_->AddRequest(&request_ptz_);
215 WaitForBubbleToBeShown();
217 EXPECT_TRUE(prompt_factory_->is_visible());
218 ASSERT_EQ(prompt_factory_->request_count(), 1);
221 // Only mic/camera/ptz requests from the same origin should be grouped.
222 TEST_F(PermissionRequestManagerTest, MicCameraPtzGrouped) {
223 manager_->AddRequest(&request_mic_);
224 manager_->AddRequest(&request_camera_);
225 manager_->AddRequest(&request_ptz_);
226 WaitForBubbleToBeShown();
228 EXPECT_TRUE(prompt_factory_->is_visible());
229 ASSERT_EQ(prompt_factory_->request_count(), 3);
232 EXPECT_TRUE(request_mic_.granted());
233 EXPECT_TRUE(request_camera_.granted());
234 EXPECT_TRUE(request_ptz_.granted());
236 // If the requests come from different origins, they should not be grouped.
237 manager_->AddRequest(&iframe_request_mic_other_domain_);
238 manager_->AddRequest(&request_camera_);
239 manager_->AddRequest(&request_ptz_);
240 WaitForBubbleToBeShown();
242 EXPECT_TRUE(prompt_factory_->is_visible());
243 ASSERT_EQ(prompt_factory_->request_count(), 1);
246 TEST_F(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
247 manager_->AddRequest(&request_mic_);
248 manager_->AddRequest(&request_camera_);
249 WaitForBubbleToBeShown();
251 EXPECT_TRUE(prompt_factory_->is_visible());
252 ASSERT_EQ(prompt_factory_->request_count(), 2);
255 #if defined(OS_ANDROID)
256 EXPECT_TRUE(prompt_factory_->is_visible());
258 EXPECT_FALSE(prompt_factory_->is_visible());
262 WaitForBubbleToBeShown();
263 EXPECT_TRUE(prompt_factory_->is_visible());
264 ASSERT_EQ(prompt_factory_->request_count(), 2);
267 EXPECT_TRUE(request_mic_.granted());
268 EXPECT_TRUE(request_camera_.granted());
271 TEST_F(PermissionRequestManagerTest, ThreeRequestsTabSwitch) {
272 manager_->AddRequest(&request_mic_);
273 manager_->AddRequest(&request_camera_);
274 manager_->AddRequest(&request_ptz_);
275 WaitForBubbleToBeShown();
277 EXPECT_TRUE(prompt_factory_->is_visible());
278 ASSERT_EQ(prompt_factory_->request_count(), 3);
281 #if defined(OS_ANDROID)
282 EXPECT_TRUE(prompt_factory_->is_visible());
284 EXPECT_FALSE(prompt_factory_->is_visible());
288 WaitForBubbleToBeShown();
289 EXPECT_TRUE(prompt_factory_->is_visible());
290 ASSERT_EQ(prompt_factory_->request_count(), 3);
293 EXPECT_TRUE(request_mic_.granted());
294 EXPECT_TRUE(request_camera_.granted());
295 EXPECT_TRUE(request_ptz_.granted());
298 TEST_F(PermissionRequestManagerTest, NoRequests) {
299 WaitForBubbleToBeShown();
300 EXPECT_FALSE(prompt_factory_->is_visible());
303 TEST_F(PermissionRequestManagerTest, PermissionRequestWhileTabSwitchedAway) {
305 manager_->AddRequest(&request1_);
306 WaitForBubbleToBeShown();
307 EXPECT_FALSE(prompt_factory_->is_visible());
310 WaitForBubbleToBeShown();
311 EXPECT_TRUE(prompt_factory_->is_visible());
314 TEST_F(PermissionRequestManagerTest, TwoRequestsDoNotCoalesce) {
315 manager_->AddRequest(&request1_);
316 WaitForBubbleToBeShown();
317 manager_->AddRequest(&request2_);
319 EXPECT_TRUE(prompt_factory_->is_visible());
320 ASSERT_EQ(prompt_factory_->request_count(), 1);
323 TEST_F(PermissionRequestManagerTest, TwoRequestsShownInTwoBubbles) {
324 manager_->AddRequest(&request1_);
325 WaitForBubbleToBeShown();
326 manager_->AddRequest(&request2_);
328 EXPECT_TRUE(prompt_factory_->is_visible());
329 ASSERT_EQ(prompt_factory_->request_count(), 1);
332 WaitForBubbleToBeShown();
334 EXPECT_TRUE(prompt_factory_->is_visible());
335 ASSERT_EQ(prompt_factory_->request_count(), 1);
336 ASSERT_EQ(prompt_factory_->show_count(), 2);
339 TEST_F(PermissionRequestManagerTest, TestAddDuplicateRequest) {
340 manager_->AddRequest(&request1_);
341 manager_->AddRequest(&request1_);
343 WaitForBubbleToBeShown();
344 EXPECT_TRUE(prompt_factory_->is_visible());
345 ASSERT_EQ(prompt_factory_->request_count(), 1);
348 TEST_F(PermissionRequestManagerTest, SequentialRequests) {
349 manager_->AddRequest(&request1_);
350 WaitForBubbleToBeShown();
351 EXPECT_TRUE(prompt_factory_->is_visible());
354 EXPECT_TRUE(request1_.granted());
356 EXPECT_FALSE(prompt_factory_->is_visible());
358 manager_->AddRequest(&request2_);
359 WaitForBubbleToBeShown();
360 EXPECT_TRUE(prompt_factory_->is_visible());
362 EXPECT_FALSE(prompt_factory_->is_visible());
363 EXPECT_TRUE(request2_.granted());
366 TEST_F(PermissionRequestManagerTest, SameRequestRejected) {
367 manager_->AddRequest(&request1_);
368 manager_->AddRequest(&request1_);
369 EXPECT_FALSE(request1_.finished());
371 WaitForBubbleToBeShown();
372 EXPECT_TRUE(prompt_factory_->is_visible());
373 ASSERT_EQ(prompt_factory_->request_count(), 1);
376 TEST_F(PermissionRequestManagerTest, DuplicateQueuedRequest) {
377 manager_->AddRequest(&request1_);
378 WaitForBubbleToBeShown();
379 manager_->AddRequest(&request2_);
381 MockPermissionRequest dupe_request("test1");
382 manager_->AddRequest(&dupe_request);
383 EXPECT_FALSE(dupe_request.finished());
384 EXPECT_FALSE(request1_.finished());
386 MockPermissionRequest dupe_request2("test2");
387 manager_->AddRequest(&dupe_request2);
388 EXPECT_FALSE(dupe_request2.finished());
389 EXPECT_FALSE(request2_.finished());
392 EXPECT_TRUE(dupe_request.finished());
393 EXPECT_TRUE(request1_.finished());
395 WaitForBubbleToBeShown();
397 EXPECT_TRUE(dupe_request2.finished());
398 EXPECT_TRUE(request2_.finished());
401 TEST_F(PermissionRequestManagerTest, ForgetRequestsOnPageNavigation) {
402 manager_->AddRequest(&request1_);
403 WaitForBubbleToBeShown();
404 manager_->AddRequest(&request2_);
405 manager_->AddRequest(&iframe_request_other_domain_);
407 EXPECT_TRUE(prompt_factory_->is_visible());
408 ASSERT_EQ(prompt_factory_->request_count(), 1);
410 NavigateAndCommit(GURL("http://www2.google.com/"));
411 WaitForBubbleToBeShown();
413 EXPECT_FALSE(prompt_factory_->is_visible());
414 EXPECT_TRUE(request1_.finished());
415 EXPECT_TRUE(request2_.finished());
416 EXPECT_TRUE(iframe_request_other_domain_.finished());
419 TEST_F(PermissionRequestManagerTest, MainFrameNoRequestIFrameRequest) {
420 manager_->AddRequest(&iframe_request_same_domain_);
421 WaitForBubbleToBeShown();
424 EXPECT_TRUE(prompt_factory_->is_visible());
426 EXPECT_TRUE(iframe_request_same_domain_.finished());
429 TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestSameDomain) {
430 manager_->AddRequest(&request1_);
431 manager_->AddRequest(&iframe_request_same_domain_);
433 WaitForBubbleToBeShown();
435 EXPECT_TRUE(prompt_factory_->is_visible());
436 ASSERT_EQ(1, prompt_factory_->request_count());
438 EXPECT_TRUE(request1_.finished());
439 EXPECT_FALSE(iframe_request_same_domain_.finished());
440 WaitForBubbleToBeShown();
441 EXPECT_TRUE(prompt_factory_->is_visible());
442 ASSERT_EQ(1, prompt_factory_->request_count());
444 EXPECT_FALSE(prompt_factory_->is_visible());
445 EXPECT_TRUE(iframe_request_same_domain_.finished());
448 TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestOtherDomain) {
449 manager_->AddRequest(&request1_);
450 manager_->AddRequest(&iframe_request_other_domain_);
452 WaitForBubbleToBeShown();
454 EXPECT_TRUE(prompt_factory_->is_visible());
456 EXPECT_TRUE(request1_.finished());
457 EXPECT_FALSE(iframe_request_other_domain_.finished());
458 EXPECT_TRUE(prompt_factory_->is_visible());
460 EXPECT_TRUE(iframe_request_other_domain_.finished());
463 TEST_F(PermissionRequestManagerTest, IFrameRequestWhenMainRequestVisible) {
464 manager_->AddRequest(&request1_);
465 WaitForBubbleToBeShown();
466 EXPECT_TRUE(prompt_factory_->is_visible());
468 manager_->AddRequest(&iframe_request_same_domain_);
470 ASSERT_EQ(prompt_factory_->request_count(), 1);
472 EXPECT_TRUE(request1_.finished());
473 EXPECT_FALSE(iframe_request_same_domain_.finished());
474 EXPECT_TRUE(prompt_factory_->is_visible());
475 ASSERT_EQ(prompt_factory_->request_count(), 1);
477 EXPECT_TRUE(iframe_request_same_domain_.finished());
480 TEST_F(PermissionRequestManagerTest,
481 IFrameRequestOtherDomainWhenMainRequestVisible) {
482 manager_->AddRequest(&request1_);
483 WaitForBubbleToBeShown();
484 EXPECT_TRUE(prompt_factory_->is_visible());
486 manager_->AddRequest(&iframe_request_other_domain_);
489 EXPECT_TRUE(request1_.finished());
490 EXPECT_FALSE(iframe_request_other_domain_.finished());
491 EXPECT_TRUE(prompt_factory_->is_visible());
493 EXPECT_TRUE(iframe_request_other_domain_.finished());
496 TEST_F(PermissionRequestManagerTest, RequestsDontNeedUserGesture) {
498 WaitForBubbleToBeShown();
499 manager_->AddRequest(&request1_);
500 manager_->AddRequest(&iframe_request_other_domain_);
501 manager_->AddRequest(&request2_);
502 base::RunLoop().RunUntilIdle();
504 EXPECT_TRUE(prompt_factory_->is_visible());
507 // This code path (calling Accept on a non-merged bubble, with no accepted
508 // permission) would never be used in actual Chrome, but its still tested for
510 TEST_F(PermissionRequestManagerTest, UMAForSimpleDeniedBubbleAlternatePath) {
511 base::HistogramTester histograms;
513 manager_->AddRequest(&request1_);
514 WaitForBubbleToBeShown();
515 // No need to test UMA for showing prompts again, they were tested in
516 // UMAForSimpleAcceptedBubble.
519 histograms.ExpectUniqueSample(
520 PermissionUmaUtil::kPermissionsPromptDenied,
521 static_cast<base::HistogramBase::Sample>(PermissionRequestType::QUOTA),
525 TEST_F(PermissionRequestManagerTest, UMAForTabSwitching) {
526 base::HistogramTester histograms;
528 manager_->AddRequest(&request1_);
529 WaitForBubbleToBeShown();
530 histograms.ExpectUniqueSample(
531 PermissionUmaUtil::kPermissionsPromptShown,
532 static_cast<base::HistogramBase::Sample>(PermissionRequestType::QUOTA),
537 histograms.ExpectUniqueSample(
538 PermissionUmaUtil::kPermissionsPromptShown,
539 static_cast<base::HistogramBase::Sample>(PermissionRequestType::QUOTA),
543 // Simulate a NotificationPermissionUiSelector that simply returns a
544 // predefined |ui_to_use| every time.
545 class MockNotificationPermissionUiSelector
546 : public NotificationPermissionUiSelector {
548 explicit MockNotificationPermissionUiSelector(
549 base::Optional<QuietUiReason> quiet_ui_reason,
551 quiet_ui_reason_ = quiet_ui_reason;
555 void SelectUiToUse(PermissionRequest* request,
556 DecisionMadeCallback callback) override {
557 Decision decision(quiet_ui_reason_, Decision::ShowNoWarning());
559 base::SequencedTaskRunnerHandle::Get()->PostTask(
560 FROM_HERE, base::BindOnce(std::move(callback), decision));
562 std::move(callback).Run(decision);
566 static void CreateForManager(PermissionRequestManager* manager,
567 base::Optional<QuietUiReason> quiet_ui_reason,
569 manager->set_notification_permission_ui_selector_for_testing(
570 std::make_unique<MockNotificationPermissionUiSelector>(quiet_ui_reason,
575 base::Optional<QuietUiReason> quiet_ui_reason_;
579 TEST_F(PermissionRequestManagerTest,
580 UiSelectorNotUsedForPermissionsOtherThanNotification) {
581 for (auto* request : {&request_mic_, &request_camera_, &request_ptz_}) {
582 MockNotificationPermissionUiSelector::CreateForManager(
584 NotificationPermissionUiSelector::QuietUiReason::kEnabledInPrefs,
587 manager_->AddRequest(request);
588 WaitForBubbleToBeShown();
590 ASSERT_TRUE(prompt_factory_->is_visible());
592 prompt_factory_->RequestTypeSeen(request->GetPermissionRequestType()));
593 EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
596 EXPECT_TRUE(request->granted());
600 TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
602 base::Optional<NotificationPermissionUiSelector::QuietUiReason>
606 {QuietUiReason::kEnabledInPrefs, true},
607 {NotificationPermissionUiSelector::Decision::UseNormalUi(), true},
608 {QuietUiReason::kEnabledInPrefs, false},
609 {NotificationPermissionUiSelector::Decision::UseNormalUi(), false},
612 for (const auto& test : kTests) {
613 MockNotificationPermissionUiSelector::CreateForManager(
614 manager_, test.quiet_ui_reason, test.async);
616 MockPermissionRequest request(
617 "foo", PermissionRequestType::PERMISSION_NOTIFICATIONS,
618 PermissionRequestGestureType::GESTURE);
620 manager_->AddRequest(&request);
621 WaitForBubbleToBeShown();
623 EXPECT_TRUE(prompt_factory_->is_visible());
625 prompt_factory_->RequestTypeSeen(request.GetPermissionRequestType()));
626 EXPECT_EQ(!!test.quiet_ui_reason,
627 manager_->ShouldCurrentRequestUseQuietUI());
630 EXPECT_TRUE(request.granted());
634 TEST_F(PermissionRequestManagerTest,
635 UiSelectionHappensSeparatelyForEachRequest) {
636 using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
637 MockNotificationPermissionUiSelector::CreateForManager(
638 manager_, QuietUiReason::kEnabledInPrefs, true);
639 MockPermissionRequest request1(
640 "request1", PermissionRequestType::PERMISSION_NOTIFICATIONS,
641 PermissionRequestGestureType::GESTURE);
642 manager_->AddRequest(&request1);
643 WaitForBubbleToBeShown();
644 EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI());
647 MockPermissionRequest request2(
648 "request2", PermissionRequestType::PERMISSION_NOTIFICATIONS,
649 PermissionRequestGestureType::GESTURE);
650 MockNotificationPermissionUiSelector::CreateForManager(
651 manager_, NotificationPermissionUiSelector::Decision::UseNormalUi(),
653 manager_->AddRequest(&request2);
654 WaitForBubbleToBeShown();
655 EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
659 TEST_F(PermissionRequestManagerTest, RequestsNotSupported) {
660 manager_->AddRequest(&request1_);
661 WaitForBubbleToBeShown();
663 EXPECT_TRUE(request1_.granted());
665 manager_->set_web_contents_supports_permission_requests(false);
667 manager_->AddRequest(&request2_);
668 EXPECT_TRUE(request2_.cancelled());
670 } // namespace permissions