chromium/components/permissions/permission_request_manager_unittest.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/permissions/permission_request_manager.h"

#include <stddef.h>

#include <memory>
#include <optional>
#include <string>

#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_ui_selector.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/request_type.h"
#include "components/permissions/test/mock_permission_prompt_factory.h"
#include "components/permissions/test/mock_permission_request.h"
#include "components/permissions/test/test_permissions_client.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"

namespace permissions {

namespace {
QuietUiReason;
}

class PermissionRequestManagerTest : public content::RenderViewHostTestHarness {};

////////////////////////////////////////////////////////////////////////////////
// General
////////////////////////////////////////////////////////////////////////////////

TEST_F(PermissionRequestManagerTest, NoRequests) {}

TEST_F(PermissionRequestManagerTest, SingleRequest) {}

TEST_F(PermissionRequestManagerTest, SequentialRequests) {}

TEST_F(PermissionRequestManagerTest, ForgetRequestsOnPageNavigation) {}

TEST_F(PermissionRequestManagerTest, RequestsDontNeedUserGesture) {}

TEST_F(PermissionRequestManagerTest, RequestsNotSupported) {}

////////////////////////////////////////////////////////////////////////////////
// Requests grouping
////////////////////////////////////////////////////////////////////////////////

// Android is the only platform that does not support the permission chip.
#if BUILDFLAG(IS_ANDROID)
// Most requests should never be grouped.
// Grouping for chip feature is tested in ThreeRequestsStackOrderChip.
TEST_F(PermissionRequestManagerTest, TwoRequestsUngrouped) {
  manager_->AddRequest(web_contents()->GetPrimaryMainFrame(), &request1_);
  manager_->AddRequest(web_contents()->GetPrimaryMainFrame(), &request2_);

  WaitForBubbleToBeShown();
  EXPECT_TRUE(prompt_factory_->is_visible());
  ASSERT_EQ(prompt_factory_->request_count(), 1);
  Accept();
  EXPECT_TRUE(request1_.granted());

  WaitForBubbleToBeShown();
  EXPECT_TRUE(prompt_factory_->is_visible());
  ASSERT_EQ(prompt_factory_->request_count(), 1);
  Accept();
  EXPECT_TRUE(request2_.granted());

  ASSERT_EQ(prompt_factory_->show_count(), 2);
}

// Tests for non-Android platforms which support the permission chip.
#else   // BUILDFLAG(IS_ANDROID)
TEST_F(PermissionRequestManagerTest, ThreeRequestsStackOrderChip) {}

// Test new permissions order by adding requests one at a time.
TEST_F(PermissionRequestManagerTest, ThreeRequestsOneByOneStackOrderChip) {}
#endif  // BUILDFLAG(IS_ANDROID)

// Only mic/camera requests from the same origin should be grouped.
TEST_F(PermissionRequestManagerTest, MicCameraGrouped) {}

// If mic/camera requests come from different origins, they should not be
// grouped.
TEST_F(PermissionRequestManagerTest, MicCameraDifferentOrigins) {}

#if !BUILDFLAG(IS_ANDROID)
// Only camera/ptz requests from the same origin should be grouped.
TEST_F(PermissionRequestManagerTest, CameraPtzGrouped) {}

TEST_F(PermissionRequestManagerTest, CameraPtzDifferentOrigins) {}

// Only mic/camera/ptz requests from the same origin should be grouped.
TEST_F(PermissionRequestManagerTest, MicCameraPtzGrouped) {}

// If mic/camera/ptz requests come from different origins, they should not be
// grouped.
TEST_F(PermissionRequestManagerTest, MicCameraPtzDifferentOrigins) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Tests mix of grouped media requests and non-groupable request.
TEST_F(PermissionRequestManagerTest, MixOfMediaAndNotMediaRequests) {}

TEST_F(PermissionRequestManagerTest, OpenHelpCenterLink) {}

TEST_F(PermissionRequestManagerTest, OpenHelpCenterLink_RequestNotSupported) {}

////////////////////////////////////////////////////////////////////////////////
// Tab switching
////////////////////////////////////////////////////////////////////////////////

#if BUILDFLAG(IS_ANDROID)
TEST_F(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
  manager_->AddRequest(web_contents()->GetPrimaryMainFrame(), &request_mic_);
  manager_->AddRequest(web_contents()->GetPrimaryMainFrame(), &request_camera_);
  WaitForBubbleToBeShown();

  EXPECT_TRUE(prompt_factory_->is_visible());
  ASSERT_EQ(prompt_factory_->request_count(), 2);

  MockTabSwitchAway();
  EXPECT_TRUE(prompt_factory_->is_visible());

  MockTabSwitchBack();
  WaitForBubbleToBeShown();
  EXPECT_TRUE(prompt_factory_->is_visible());
  ASSERT_EQ(prompt_factory_->request_count(), 2);

  Accept();
  EXPECT_TRUE(request_mic_.granted());
  EXPECT_TRUE(request_camera_.granted());
}
#endif  // BUILDFLAG(IS_ANDROID)

TEST_F(PermissionRequestManagerTest, PermissionRequestWhileTabSwitchedAway) {}

////////////////////////////////////////////////////////////////////////////////
// Duplicated requests
////////////////////////////////////////////////////////////////////////////////

TEST_F(PermissionRequestManagerTest, SameRequestRejected) {}

TEST_F(PermissionRequestManagerTest, WeakDuplicateRequests) {}

class QuicklyDeletedRequest : public PermissionRequest {};

TEST_F(PermissionRequestManagerTest, WeakDuplicateRequestsAccept) {}

TEST_F(PermissionRequestManagerTest, DuplicateRequest) {}

////////////////////////////////////////////////////////////////////////////////
// Requests from iframes
////////////////////////////////////////////////////////////////////////////////

TEST_F(PermissionRequestManagerTest, MainFrameNoRequestIFrameRequest) {}

TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestSameDomain) {}

TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestOtherDomain) {}

TEST_F(PermissionRequestManagerTest, IFrameRequestWhenMainRequestVisible) {}

TEST_F(PermissionRequestManagerTest,
       IFrameRequestOtherDomainWhenMainRequestVisible) {}

////////////////////////////////////////////////////////////////////////////////
// UMA logging
////////////////////////////////////////////////////////////////////////////////

// This code path (calling Accept on a non-merged bubble, with no accepted
// permission) would never be used in actual Chrome, but its still tested for
// completeness.
TEST_F(PermissionRequestManagerTest, UMAForSimpleDeniedBubbleAlternatePath) {}

TEST_F(PermissionRequestManagerTest, UMAForTabSwitching) {}

////////////////////////////////////////////////////////////////////////////////
// UI selectors
////////////////////////////////////////////////////////////////////////////////

// Simulate a PermissionUiSelector that simply returns a predefined |ui_to_use|
// every time.
class MockNotificationPermissionUiSelector : public PermissionUiSelector {};

// Same as the MockNotificationPermissionUiSelector but handling only the
// Camera stream request type
class MockCameraStreamPermissionUiSelector
    : public MockNotificationPermissionUiSelector {};

TEST_F(PermissionRequestManagerTest,
       UiSelectorNotUsedForPermissionsOtherThanNotification) {}

TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {}

TEST_F(PermissionRequestManagerTest,
       UiSelectionHappensSeparatelyForEachRequest) {}

TEST_F(PermissionRequestManagerTest, SkipNextUiSelector) {}

TEST_F(PermissionRequestManagerTest, MultipleUiSelectors) {}

TEST_F(PermissionRequestManagerTest, SelectorsPredictionLikelihood) {}

TEST_F(PermissionRequestManagerTest, SelectorRequestTypes) {}

////////////////////////////////////////////////////////////////////////////////
// Quiet UI chip. Low priority for Notifications & Geolocation.
////////////////////////////////////////////////////////////////////////////////

TEST_F(PermissionRequestManagerTest, NotificationsSingleBubbleAndChipRequest) {}

// Android is the only platform that does not support the permission chip.
#if BUILDFLAG(IS_ANDROID)
// Quiet UI feature is disabled. Chip is disabled. No low priority requests, the
// first request is always shown.
//
// Permissions requested in order:
// 1. Notification (non abusive)
// 2. Geolocation
// 3. Camera
//
// Prompt display order:
// 1. Notification request shown
// 2. Geolocation request shown
// 3. Camera request shown
TEST_F(PermissionRequestManagerTest,
       NotificationsGeolocationCameraBubbleRequest) {
  std::unique_ptr<MockPermissionRequest> request_notifications =
      CreateAndAddRequest(RequestType::kNotifications, /*should_be_seen=*/true,
                          1);
  std::unique_ptr<MockPermissionRequest> request_geolocation =
      CreateAndAddRequest(RequestType::kGeolocation, /*should_be_seen=*/false,
                          1);
  std::unique_ptr<MockPermissionRequest> request_camera = CreateAndAddRequest(
      RequestType::kCameraStream, /*should_be_seen=*/false, 1);

  for (auto* kRequest : {request_notifications.get(), request_geolocation.get(),
                         request_camera.get()}) {
    WaitAndAcceptPromptForRequest(kRequest);
  }

  EXPECT_EQ(prompt_factory_->show_count(), 3);
}

// Tests for non-Android platforms which support the permission chip.
#else  // BUILDFLAG(IS_ANDROID)
// Quiet UI feature is disabled, no low priority requests, the last request is
// always shown.
//
// Permissions requested in order:
// 1. Camera
// 2. Clipboard
// 3. MIDI
//
// Prompt display order:
// 1. Camera request shown but is preempted
// 2. Clipboard request shown but is preempted
// 3. MIDI request shown
// 4. Clipboard request shown again
// 5. Camera request shown again
TEST_F(PermissionRequestManagerTest,
       CameraNotificationsGeolocationChipRequest) {}

// Verifies order of simultaneous requests, with quiet chip enabled.
// Simultaneous new requests are coming while we are waiting for UI selector
// decisions.
//
// Permissions requested in order:
// 1. Geolocation, UI selector takes 2 seconds to decide.
// 2. Notification then mic. Notification will preempt geolocation
//
// Prompt display order:
// 1. Mic
// 2. Clipboard
// 3. Geolocation
TEST_F(PermissionRequestManagerTest, NewHighPriorityRequestDuringUIDecision) {}

// Verifies that the quiet UI chip is not ignored if another request came in
// less than 8.5 seconds after.
// Permissions requested in order:
// 1. Notification (abusive)
// 2. After less than 8.5 seconds Geolocation
//
// Prompt display order:
// 1. Notifications request shown but is preempted because of quiet UI.
// 2. Geolocation request shown
// 3. Notifications request shown again
TEST_F(PermissionRequestManagerTest,
       AbusiveNotificationsGeolocationQuietUIChipRequest) {}

// Verifies that the quiet UI chip is ignored if another request came in more
// than 8.5 seconds after.
//
// Permissions requested in order:
// 1. Notification (abusive)
// 2. After more than 8.5 seconds Geolocation
//
// Prompt display order:
// 1. Notifications request shown but is preempted because of quiet UI.
// 2. Geolocation request shown
TEST_F(PermissionRequestManagerTest, AbusiveNotificationsShownLongEnough) {}

// Verifies that the quiet UI chip is not ignored if another request came in
// more than 8.5 seconds after. Verify different requests priority. Camera
// request is shown despite being requested last.
//
// Permissions requested in order:
// 1. Notification (abusive)
// 2. After less than 8.5 seconds Geolocation
// 3. Camera
//
// Prompt display order:
// 1. Notifications request shown but is preempted because of quiet UI.
// 2. Geolocation request shown but is preempted because of low priority.
// 3. Camera request shown
// 4. Geolocation request shown again
// 5. Notifications quiet UI request shown again
TEST_F(PermissionRequestManagerTest,
       AbusiveNotificationsShownLongEnoughCamera) {}

// Verifies that the quiet UI chip is not ignored if another request came in
// more than 8.5 seconds after. Verify different requests priority. Camera
// request is not preemted.
//
// Permissions requested in order:
// 1. Camera
// 2. Notification (abusive)
// 3. After less than 8.5 seconds Geolocation
//
// Prompt display order:
// 1. Camera request shown
// 2. Geolocation request shown
// 3. Camera request shown
TEST_F(PermissionRequestManagerTest, CameraAbusiveNotificationsGeolocation) {}

// Verifies that the quiet UI chip is not ignored if another request came in
// more than 8.5 seconds after. Verify different requests priority. Camera
// request is not preemted.
//
// Permissions requested in order:
// 1. Camera
// 2. Notification (abusive)
// 3. After less than 8.5 seconds Geolocation
// 4. MIDI
//
// Prompt display order:
// 1. Camera request shown
// 2. MIDI request shown (or MIDI and then Camera, the order depends on
// `PermissionUtil::DoesPlatformSupportChip()`)
// 3. Geolocation request shown
// 4. Notifications request shown
// If Chip is enabled MIDI will replace Camera, hence 5 prompts will be
// shown. Otherwise 4.
TEST_F(PermissionRequestManagerTest,
       CameraAbusiveNotificationsGeolocationMIDI) {}

// Verifies that non abusive chip behaves similar to others when Quiet UI Chip
// is enabled.
//
// Permissions requested in order:
// 1. Camera
// 2. Notification (non abusive)
// 3. After less than 8.5 seconds Geolocation
// 4. MIDI
//
// Prompt display order:
// 1. Camera request shown
// 2. MIDI request shown (or MIDI and then Camera, the order depends on
// `PermissionUtil::DoesPlatformSupportChip()`)
// 3. Geolocation request shown
// 4. Notifications request shown
// If Chip is enabled MIDI will replace Camera, hence 5 prompts will be
// shown. Otherwise 4.
TEST_F(PermissionRequestManagerTest,
       CameraNonAbusiveNotificationsGeolocationMIDI) {}

// Verifies order of requests with mixed low-high priority requests input, with
// both chip and quiet chip enabled. New permissions are added and accepted one
// by one.
//
// Permissions requested in order:
// 1. Multiple Download (high)
// 2. Geolocation (low)
// 3. Mic (high)
//
// Prompt display order:
// 1. Mic
// 2. Multiple Download
// 3. Geolocation
TEST_F(PermissionRequestManagerTest, Mixed1Low2HighPriorityRequests) {}

// Verifies order of requests with mixed low-high priority requests input, with
// both chip and quiet chip enabled. New permissions are added and accepted one
// by one.
//
// Permissions requested in order:
// 1. Geolocation (low)
// 2. Mic (high)
// 3. Notification (low)
//
// Prompt display order:
// 1. Mic
// 2. Notification
// 3. Geolocation
TEST_F(PermissionRequestManagerTest, Mixed2Low1HighRequests) {}

// Verifies order of requests with mixed low-high priority requests input, added
// simultaneously, with both chip and quiet chip enabled.
//
// Permissions requested in order:
// 1. Geolocation (low)
// 2. Mic (high)
// 3. Notification (low)
//
// Prompt display order:
// 1. Mic
// 2. Notification
// 3. Geolocation
TEST_F(PermissionRequestManagerTest, MultipleSimultaneous2Low1HighRequests) {}

// Verifies order of requests with mixed low-high priority requests input,
// added simultaneously, with both chip and quiet chip enabled.
//
// Permissions requested in order:
// 1. MIDI (high)
// 2. Geolocation (low)
// 3. Mic (high)
// 4. Notification (low)
// 5. Multiple Download (high)
//
// Prompt display order:
// 1. Multiple Download
// 2. Mic
// 3. Midi
// 4. Notification
// 5. Geolocation
TEST_F(PermissionRequestManagerTest, MultipleSimultaneous2Low3HighRequests) {}

// Verifies order of requests with mixed low-high priority requests input, added
// simultaneously several times, with both chip and quiet chip enabled.
//
// Permissions requested in order:
// 1. Geolocation(low) then Notification(low)
// 2. Mic (high) then multiple downloads (high)
// Prompt display order:
// 1. Multiple Download
// 2. Mic
// 3. Notification
// 4. Geolocation
TEST_F(PermissionRequestManagerTest, MultipleSimultaneous2Low2HighRequests) {}

TEST_F(PermissionRequestManagerTest, PEPCRequestNeverQuiet) {}

#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace permissions