blob: 328fff5887fc0bcc9ac7c040a5798353b6c4d9d8 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <optional>
#include "base/time/time.h"
#include "chrome/browser/ui/hats/hats_service.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/permissions/constants.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_hats_trigger_helper.h"
#include "components/permissions/permission_request_enums.h"
#include "components/permissions/permission_uma_util.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
class PermissionHatsTriggerUnitTest : public testing::Test {
public:
PermissionHatsTriggerUnitTest() {
trigger_gurl = std::make_optional(GURL("https://test.url"));
}
PermissionHatsTriggerUnitTest(const PermissionHatsTriggerUnitTest&) = delete;
PermissionHatsTriggerUnitTest& operator=(
const PermissionHatsTriggerUnitTest&) = delete;
protected:
void SetUp() override {
permissions::PermissionHatsTriggerHelper::SetIsTest();
}
struct FeatureParams {
std::string trigger_id = "pqEK9eaX30ugnJ3q1cK0UsVJTo1z";
std::string probability_vector = "1.0";
std::string action_filter = "";
std::string request_type_filter = "";
std::string prompt_disposition_filter = "";
std::string prompt_disposition_reason_filter = "";
std::string had_gesture_filter = "";
std::string release_channel_filter = "beta";
std::string ignored_prompts_maximum_age = "10m";
std::string survey_display_time = "OnPromptResolved";
std::string one_time_prompts_decided_bucket = "";
std::string pepc_prompt_position_filter = "";
std::string initial_permission_status_filter = "";
};
void SetupFeatureParams(FeatureParams params) {
feature_list()->InitWithFeaturesAndParameters(
{{permissions::features::kPermissionsPromptSurvey,
{{"trigger_id", params.trigger_id},
{"probability_vector", params.probability_vector},
{"action_filter", params.action_filter},
{"request_type_filter", params.request_type_filter},
{"prompt_disposition_filter", params.prompt_disposition_filter},
{"prompt_disposition_reason_filter",
params.prompt_disposition_reason_filter},
{"had_gesture_filter", params.had_gesture_filter},
{"release_channel_filter", params.release_channel_filter},
{"ignored_prompts_maximum_age", params.ignored_prompts_maximum_age},
{"survey_display_time", params.survey_display_time},
{"one_time_prompts_decided_bucket",
params.one_time_prompts_decided_bucket},
{"pepc_prompt_position_filter", params.pepc_prompt_position_filter},
{"initial_permission_status_filter",
params.initial_permission_status_filter}}}},
{});
}
base::test::ScopedFeatureList* feature_list() { return &feature_list_; }
// Represents the url on which the survey was triggered
std::optional<GURL> trigger_gurl;
private:
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::test::ScopedFeatureList feature_list_;
};
TEST_F(PermissionHatsTriggerUnitTest, SingleValuedFiltersTriggerCorrectly) {
FeatureParams params;
params.action_filter = "Accepted";
params.request_type_filter = "Notifications";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// // Wrong action, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// // Wrong request type, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong prompt disposition, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::MESSAGE_UI,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong prompt disposition reason, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
SAFE_BROWSING_VERDICT,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// No gesture, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::NO_GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong channel, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::NO_GESTURE,
"stable", permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, EmptyFiltersShouldAlwaysTrigger) {
FeatureParams params;
// The same logic is reused for all filters. As representative example this
// test configures and tests an empty string for the action filter. The empty
// string is also the default value used by the feature flag, if no value is
// set.
params.action_filter = "";
params.request_type_filter = "Notifications";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED_ONCE,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, CSVFiltersTriggerForAllConfiguredValues) {
FeatureParams params;
// The same logic is reused for all filters. As representative example this
// test configures a CSV for the action filter.
params.action_filter = "Accepted,Dismissed";
params.request_type_filter = "Notifications";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong action, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong action, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED_ONCE,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong action, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong one time prompt count bucket, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_6_10,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, FilterConfigurationHandlesEdgeCases) {
FeatureParams params;
params.action_filter =
" Accepted , Dismissed "; // arbitrary whitespace between distinct
// filter values
params.request_type_filter =
"Notifications,Geolocation,Notifications"; // same value twice
params.prompt_disposition_filter = "ANCHOREDBUBBLE"; // case insensitive
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, ProductSpecificFieldsAreReported) {
FeatureParams params;
params.action_filter = "Accepted";
params.request_type_filter = "Notifications";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
SetupFeatureParams(params);
auto survey_data = permissions::PermissionHatsTriggerHelper::
SurveyProductSpecificData::PopulateFrom(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_6_10,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT));
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionsPromptSurveyHadGestureKey),
true);
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewVisibleKey),
false);
EXPECT_EQ(
survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewDropdownInteractedKey),
false);
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewWasCombinedKey),
false);
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyPromptDispositionKey),
"AnchoredBubble");
EXPECT_EQ(
survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyPromptDispositionReasonKey),
"DefaultFallback");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyActionKey),
"Accepted");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyRequestTypeKey),
"Notifications");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyReleaseChannelKey),
"beta");
EXPECT_EQ(
survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyOneTimePromptsDecidedBucketKey),
"6_10");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyUrlKey),
trigger_gurl);
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyPreviewTimeToDecisionKey),
"");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyPreviewTimeToVisibleKey),
"");
}
TEST_F(PermissionHatsTriggerUnitTest, ExtraProductSpecificFieldsAreReported) {
FeatureParams params;
params.action_filter = "Accepted";
params.request_type_filter = "VideoCapture";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
SetupFeatureParams(params);
auto survey_data = permissions::PermissionHatsTriggerHelper::
SurveyProductSpecificData::PopulateFrom(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_6_10,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT,
std::make_optional<permissions::PermissionHatsTriggerHelper::
PreviewParametersForHats>(
/*was_visible=*/true, /*dropdown_was_interacted=*/false,
/*was_prompt_combined=*/true,
/*time_to_decision=*/base::Milliseconds(12345),
/*time_to_visible=*/base::Milliseconds(98765))));
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionsPromptSurveyHadGestureKey),
true);
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewVisibleKey),
true);
EXPECT_EQ(
survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewDropdownInteractedKey),
false);
EXPECT_EQ(survey_data.survey_bits_data.at(
permissions::kPermissionPromptSurveyPreviewWasCombinedKey),
true);
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyPromptDispositionKey),
"AnchoredBubble");
EXPECT_EQ(
survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyPromptDispositionReasonKey),
"DefaultFallback");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyActionKey),
"Accepted");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyRequestTypeKey),
"VideoCapture");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionsPromptSurveyReleaseChannelKey),
"beta");
EXPECT_EQ(
survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyOneTimePromptsDecidedBucketKey),
"6_10");
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyUrlKey),
trigger_gurl);
// Time deltas should be stringified and rounded to the nearest
// 100-millisecond interval:
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyPreviewTimeToDecisionKey),
"12300"); // N.B.: rounded down
EXPECT_EQ(survey_data.survey_string_data.at(
permissions::kPermissionPromptSurveyPreviewTimeToVisibleKey),
"98800"); // N.B.: rounded up
}
TEST_F(PermissionHatsTriggerUnitTest, VerifyIgnoreSafeguardFunctionality) {
FeatureParams params;
params.action_filter = "Ignored";
params.request_type_filter = "Notifications";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
params.ignored_prompts_maximum_age = "10m";
SetupFeatureParams(params);
// The safeguard is active, but the display time is less than the configured
// value. Thus, this should trigger.
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(5),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// The safeguard is active, and the display time is higher than the configured
// value. Thus, this should not trigger.
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(15),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, VerifyUnconfiguredFiltersSafeguard) {
// No filter at all configured
FeatureParams params;
params.action_filter = "";
params.request_type_filter = "";
params.prompt_disposition_filter = "";
params.prompt_disposition_reason_filter = "";
params.had_gesture_filter = "";
params.release_channel_filter = "";
params.survey_display_time = "";
SetupFeatureParams(params);
// Matching call, but should not trigger due to safeguard
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, VerifyMisconfiguredFiltersSafeguard) {
FeatureParams params;
params.action_filter = "asdf";
params.request_type_filter = "";
params.prompt_disposition_filter = "";
params.prompt_disposition_reason_filter = "";
params.had_gesture_filter = "";
params.release_channel_filter = "";
SetupFeatureParams(params);
// One filter is configured with a nonsensical value, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kNotifications,
permissions::PermissionAction::IGNORED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, MultipleTriggersShouldWorkCorrectly) {
FeatureParams params;
params.trigger_id = "trig1,trig2,trig3";
params.probability_vector = "1.0,1.0,0.0";
params.request_type_filter = "Geolocation,AudioCapture,VideoCapture";
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Matching call, but 0.0 probability configured for camera, should not
// trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Request type doesn't match, should not trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraPanTiltZoom,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest,
MultipleTriggersMisconfiguredProbabilityVectorShouldNotTrigger) {
FeatureParams params;
params.trigger_id = "trig1,trig2,trig3";
params.probability_vector =
"1.0,1.0"; // 3 triggers, but probability vector of size 2 --> wrong
params.action_filter = "Accepted,Dismissed";
params.request_type_filter = "Geolocation,AudioCapture,VideoCapture";
params.prompt_disposition_filter = "AnchoredBubble";
params.prompt_disposition_reason_filter = "DefaultFallback";
params.had_gesture_filter = "true";
params.release_channel_filter = "beta";
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest,
MultipleTriggersMisconfiguredRequestTypeFilterShouldNotTrigger) {
FeatureParams params;
params.trigger_id = "trig1,trig2,trig3";
params.probability_vector = "1.0,1.0,0.0";
params.request_type_filter =
"Geolocation,AudioCapture"; // 3 trigger_ids but only 2 request types
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest,
MultipleTriggersEmptyRequestTypeFilterMisconfigurationShouldNotTrigger) {
FeatureParams params;
params.trigger_id = "trig1,trig2,trig3";
params.probability_vector = "1.0,1.0,0.0";
params.request_type_filter = ""; // No request type filter
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DISMISSED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest,
MultipleTriggersMalformedProbabilityVectorShouldNotTrigger) {
FeatureParams params;
params.trigger_id = "trig1,trig2,trig3";
params.probability_vector = "1.0,NoDouble,0.0";
params.request_type_filter = "Geolocation,AudioCapture,VideoCapture";
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest,
SingleTriggerNoProbabilityVectorShouldWork) {
FeatureParams params;
params.trigger_id = "trig1";
params.probability_vector = "";
params.request_type_filter = "Geolocation,AudioCapture,VideoCapture";
params.one_time_prompts_decided_bucket = "0_1,2_3,4_5";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "beta",
permissions::kOnPromptResolved, base::Minutes(1),
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_4_5,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, PepcPromptDispositionRequestTypeFilter) {
FeatureParams params;
params.action_filter = "";
params.request_type_filter = "VideoCapture";
params.prompt_disposition_filter = "ElementAnchoredBubble";
params.prompt_disposition_reason_filter = "";
params.had_gesture_filter = "";
params.release_channel_filter = "";
params.one_time_prompts_decided_bucket = "";
SetupFeatureParams(params);
// Matching call, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::UNKNOWN, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
// Wrong request type.
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::UNKNOWN, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, PepcPromptDispositionMultipleRequests) {
FeatureParams params;
params.action_filter = "Denied";
params.request_type_filter = "AudioCapture,VideoCapture";
params.prompt_disposition_filter = "ElementAnchoredBubble";
params.prompt_disposition_reason_filter = "";
params.had_gesture_filter = "true";
params.survey_display_time = "OnPromptResolved";
params.release_channel_filter = "stable";
params.one_time_prompts_decided_bucket = "";
params.ignored_prompts_maximum_age = "";
SetupFeatureParams(params);
// Matching calls, should trigger
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kGeolocation, // Wrong request type
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::GRANTED, // Wrong action
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
LOCATION_BAR_LEFT_CHIP_AUTO_BUBBLE, // Wrong disposition
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE,
"beta", // Wrong channel
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptAppearing, // Wrong display time
std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::UNKNOWN,
"stable", // Wrong gesture.
permissions::kOnPromptAppearing, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt, CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, PepcPromptPositionFilter) {
FeatureParams params;
params.request_type_filter = "AudioCapture,VideoCapture";
params.survey_display_time = "OnPromptResolved";
params.release_channel_filter = "stable";
params.pepc_prompt_position_filter = "near_element";
SetupFeatureParams(params);
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kNearElement,
CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kLegacyPrompt, // Wrong position
CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kWindowMiddle, // Wrong position
CONTENT_SETTING_DEFAULT)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kMicStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
LOCATION_BAR_LEFT_CHIP_AUTO_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
std::nullopt, // Wrong position (no position)
CONTENT_SETTING_DEFAULT)));
}
TEST_F(PermissionHatsTriggerUnitTest, PepcPromptInitialStatusFilter) {
FeatureParams params;
params.request_type_filter = "VideoCapture";
params.survey_display_time = "OnPromptAppearing";
params.release_channel_filter = "stable";
params.initial_permission_status_filter = "allow";
SetupFeatureParams(params);
EXPECT_TRUE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptAppearing, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kNearElement,
CONTENT_SETTING_ALLOW)));
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptAppearing, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kLegacyPrompt,
CONTENT_SETTING_ASK))); // Wrong initial status
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptAppearing, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl,
permissions::feature_params::PermissionElementPromptPosition::
kWindowMiddle,
CONTENT_SETTING_BLOCK))); // Wrong initial status
EXPECT_FALSE(
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::DENIED,
permissions::PermissionPromptDisposition::
LOCATION_BAR_LEFT_CHIP_AUTO_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE, "stable",
permissions::kOnPromptAppearing, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, std::nullopt,
CONTENT_SETTING_DEFAULT))); // Wrong initial status
}
TEST_F(PermissionHatsTriggerUnitTest,
PepcPromptPositionAndInitialStatusFilter) {
using permissions::feature_params::PermissionElementPromptPosition;
FeatureParams params;
params.request_type_filter = "AudioCapture,VideoCapture";
params.survey_display_time = "OnPromptResolved";
params.release_channel_filter = "stable";
params.pepc_prompt_position_filter = "window_middle,legacy_prompt";
params.initial_permission_status_filter = "block,ask";
SetupFeatureParams(params);
struct {
permissions::feature_params::PermissionElementPromptPosition position;
ContentSetting initial_status;
bool expect_satisfied;
} kTests[] = {
{PermissionElementPromptPosition::kWindowMiddle, CONTENT_SETTING_ASK,
true},
{PermissionElementPromptPosition::kLegacyPrompt, CONTENT_SETTING_ASK,
true},
{PermissionElementPromptPosition::kNearElement, CONTENT_SETTING_ASK,
false},
{PermissionElementPromptPosition::kWindowMiddle, CONTENT_SETTING_BLOCK,
true},
{PermissionElementPromptPosition::kLegacyPrompt, CONTENT_SETTING_BLOCK,
true},
{PermissionElementPromptPosition::kNearElement, CONTENT_SETTING_BLOCK,
false},
{PermissionElementPromptPosition::kWindowMiddle, CONTENT_SETTING_ALLOW,
false},
{PermissionElementPromptPosition::kLegacyPrompt, CONTENT_SETTING_ALLOW,
false},
{PermissionElementPromptPosition::kNearElement, CONTENT_SETTING_ALLOW,
false},
};
for (const auto& test : kTests) {
EXPECT_EQ(
test.expect_satisfied,
permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(
permissions::PermissionHatsTriggerHelper::
PromptParametersForHats(
permissions::RequestType::kCameraStream,
permissions::PermissionAction::GRANTED,
permissions::PermissionPromptDisposition::
ELEMENT_ANCHORED_BUBBLE,
permissions::PermissionPromptDispositionReason::
DEFAULT_FALLBACK,
permissions::PermissionRequestGestureType::GESTURE,
"stable", permissions::kOnPromptResolved, std::nullopt,
permissions::PermissionHatsTriggerHelper::
OneTimePermissionPromptsDecidedBucket::BUCKET_0_1,
trigger_gurl, test.position, test.initial_status)));
}
}