| Index: chrome/browser/permissions/permission_context_base_unittest.cc
|
| diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
|
| index fb5b4c8973d4c6bd9e43b47d89f606653de168c5..2225cadd21bd642e3f008af3a87dc65fa3a92dfd 100644
|
| --- a/chrome/browser/permissions/permission_context_base_unittest.cc
|
| +++ b/chrome/browser/permissions/permission_context_base_unittest.cc
|
| @@ -8,15 +8,19 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/command_line.h"
|
| +#include "base/feature_list.h"
|
| #include "base/macros.h"
|
| #include "base/metrics/field_trial.h"
|
| +#include "base/test/histogram_tester.h"
|
| #include "base/test/mock_entropy_provider.h"
|
| #include "build/build_config.h"
|
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
| #include "chrome/browser/infobars/infobar_service.h"
|
| +#include "chrome/browser/permissions/permission_decision_auto_blocker.h"
|
| #include "chrome/browser/permissions/permission_queue_controller.h"
|
| #include "chrome/browser/permissions/permission_request_id.h"
|
| #include "chrome/browser/permissions/permission_util.h"
|
| +#include "chrome/common/chrome_features.h"
|
| #include "chrome/common/chrome_switches.h"
|
| #include "chrome/test/base/chrome_render_view_host_test_harness.h"
|
| #include "chrome/test/base/testing_profile.h"
|
| @@ -41,6 +45,8 @@ const char* kPermissionsKillSwitchFieldStudy =
|
| const char* kPermissionsKillSwitchBlockedValue =
|
| PermissionContextBase::kPermissionsKillSwitchBlockedValue;
|
| const char kPermissionsKillSwitchTestGroup[] = "TestGroup";
|
| +const char* kPromptGroupName = kPermissionsKillSwitchTestGroup;
|
| +const char kPromptTrialName[] = "PermissionPromptsUX";
|
|
|
| class TestPermissionContext : public PermissionContextBase {
|
| public:
|
| @@ -48,9 +54,7 @@ class TestPermissionContext : public PermissionContextBase {
|
| const content::PermissionType permission_type,
|
| const ContentSettingsType content_settings_type)
|
| : PermissionContextBase(profile, permission_type, content_settings_type),
|
| - tab_context_updated_(false),
|
| - field_trial_list_(
|
| - new base::FieldTrialList(new base::MockEntropyProvider)) {}
|
| + tab_context_updated_(false) {}
|
|
|
| ~TestPermissionContext() override {}
|
|
|
| @@ -70,15 +74,6 @@ class TestPermissionContext : public PermissionContextBase {
|
| decisions_.push_back(content_setting);
|
| }
|
|
|
| - void ResetFieldTrialList() {
|
| - // Destroy the existing FieldTrialList before creating a new one to avoid
|
| - // a DCHECK.
|
| - field_trial_list_.reset();
|
| - field_trial_list_.reset(new base::FieldTrialList(
|
| - new base::MockEntropyProvider));
|
| - variations::testing::ClearAllVariationParams();
|
| - }
|
| -
|
| ContentSetting GetContentSettingFromMap(const GURL& url_a,
|
| const GURL& url_b) {
|
| return HostContentSettingsMapFactory::GetForProfile(profile())
|
| @@ -100,6 +95,28 @@ class TestPermissionContext : public PermissionContextBase {
|
| private:
|
| std::vector<ContentSetting> decisions_;
|
| bool tab_context_updated_;
|
| +};
|
| +
|
| +class TestKillSwitchPermissionContext : public TestPermissionContext {
|
| + public:
|
| + TestKillSwitchPermissionContext(
|
| + Profile* profile,
|
| + const content::PermissionType permission_type,
|
| + const ContentSettingsType content_settings_type)
|
| + : TestPermissionContext(profile, permission_type, content_settings_type),
|
| + field_trial_list_(
|
| + new base::FieldTrialList(new base::MockEntropyProvider)) {}
|
| +
|
| + void ResetFieldTrialList() {
|
| + // Destroy the existing FieldTrialList before creating a new one to avoid
|
| + // a DCHECK.
|
| + field_trial_list_.reset();
|
| + field_trial_list_.reset(new base::FieldTrialList(
|
| + new base::MockEntropyProvider));
|
| + variations::testing::ClearAllVariationParams();
|
| + }
|
| +
|
| + private:
|
| std::unique_ptr<base::FieldTrialList> field_trial_list_;
|
| };
|
|
|
| @@ -190,6 +207,172 @@ class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness {
|
| permission_context.GetContentSettingFromMap(url, url));
|
| }
|
|
|
| + void DismissMultipleTimesAndExpectBlock(
|
| + const GURL& url,
|
| + content::PermissionType permission_type,
|
| + ContentSettingsType content_settings_type,
|
| + uint32_t iterations) {
|
| + base::HistogramTester histograms;
|
| +
|
| + // Dismiss |iterations| times. The final dismiss should change the decision
|
| + // from dismiss to block, and hence change the persisted content setting.
|
| + for (uint32_t i = 0; i < iterations; ++i) {
|
| + TestPermissionContext permission_context(
|
| + profile(), permission_type, content_settings_type);
|
| + ContentSetting expected =
|
| + (i < (iterations - 1)) ? CONTENT_SETTING_ASK : CONTENT_SETTING_BLOCK;
|
| +
|
| + const PermissionRequestID id(
|
| + web_contents()->GetRenderProcessHost()->GetID(),
|
| + web_contents()->GetMainFrame()->GetRoutingID(), i);
|
| + permission_context.RequestPermission(
|
| + web_contents(), id, url, true /* user_gesture */,
|
| + base::Bind(&TestPermissionContext::TrackPermissionDecision,
|
| + base::Unretained(&permission_context)));
|
| +
|
| + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK);
|
| + histograms.ExpectTotalCount(
|
| + "Permissions.Prompt.DismissCount." +
|
| + PermissionUtil::GetPermissionString(permission_type),
|
| + i + 1);
|
| +
|
| + EXPECT_EQ(1u, permission_context.decisions().size());
|
| + EXPECT_EQ(expected, permission_context.decisions()[0]);
|
| + EXPECT_TRUE(permission_context.tab_context_updated());
|
| + EXPECT_EQ(expected,
|
| + permission_context.GetContentSettingFromMap(url, url));
|
| + }
|
| +
|
| + // Ensure that we finish in the block state.
|
| + TestPermissionContext permission_context(
|
| + profile(), permission_type, content_settings_type);
|
| + EXPECT_EQ(CONTENT_SETTING_BLOCK,
|
| + permission_context.GetContentSettingFromMap(url, url));
|
| + }
|
| +
|
| + void TestBlockOnSeveralDismissals_TestContent() {
|
| + GURL url("https://www.google.com");
|
| + NavigateAndCommit(url);
|
| + base::HistogramTester histograms;
|
| +
|
| + // First, ensure that > 3 dismissals behaves correctly.
|
| + for (uint32_t i = 0; i < 4; ++i) {
|
| + TestPermissionContext permission_context(
|
| + profile(), content::PermissionType::GEOLOCATION,
|
| + CONTENT_SETTINGS_TYPE_GEOLOCATION);
|
| +
|
| + const PermissionRequestID id(
|
| + web_contents()->GetRenderProcessHost()->GetID(),
|
| + web_contents()->GetMainFrame()->GetRoutingID(), i);
|
| + permission_context.RequestPermission(
|
| + web_contents(), id, url, true /* user_gesture */,
|
| + base::Bind(&TestPermissionContext::TrackPermissionDecision,
|
| + base::Unretained(&permission_context)));
|
| +
|
| + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK);
|
| + histograms.ExpectTotalCount("Permissions.Prompt.DismissCount.Geolocation",
|
| + i + 1);
|
| + EXPECT_EQ(1u, permission_context.decisions().size());
|
| + EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
|
| + EXPECT_TRUE(permission_context.tab_context_updated());
|
| + EXPECT_EQ(CONTENT_SETTING_ASK,
|
| + permission_context.GetContentSettingFromMap(url, url));
|
| + }
|
| +
|
| + // Flush the dismissal counts. Enable the block on too many dismissals
|
| + // feature, which is disabled by default.
|
| + HostContentSettingsMapFactory::GetForProfile(profile())
|
| + ->ClearSettingsForOneType(
|
| + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT);
|
| +
|
| + // Set up the custom parameter.
|
| + base::FieldTrialList field_trials_(nullptr);
|
| + base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
|
| + kPromptTrialName, kPromptGroupName);
|
| + base::FeatureList::ClearInstanceForTesting();
|
| + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
|
| + feature_list->RegisterFieldTrialOverride(
|
| + features::kBlockPromptsIfDismissedOften.name,
|
| + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
|
| + base::FeatureList::SetInstance(std::move(feature_list));
|
| + EXPECT_EQ(base::FeatureList::GetFieldTrial(
|
| + features::kBlockPromptsIfDismissedOften),
|
| + trial);
|
| +
|
| + EXPECT_TRUE(
|
| + base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften));
|
| +
|
| + // Sanity check independence per permission type by checking two of them.
|
| + DismissMultipleTimesAndExpectBlock(url,
|
| + content::PermissionType::GEOLOCATION,
|
| + CONTENT_SETTINGS_TYPE_GEOLOCATION, 3);
|
| + DismissMultipleTimesAndExpectBlock(url,
|
| + content::PermissionType::NOTIFICATIONS,
|
| + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, 3);
|
| + base::FeatureList::ClearInstanceForTesting();
|
| + }
|
| +
|
| + void TestVariationBlockOnSeveralDismissals_TestContent() {
|
| + GURL url("https://www.google.com");
|
| + NavigateAndCommit(url);
|
| +
|
| + // Set up the custom parameter and custom value.
|
| + base::FieldTrialList field_trials_(nullptr);
|
| + base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
|
| + kPromptTrialName, kPromptGroupName);
|
| + std::map<std::string, std::string> params;
|
| + params[PermissionDecisionAutoBlocker::kPromptDismissCountKey] = "5";
|
| + ASSERT_TRUE(variations::AssociateVariationParams(
|
| + kPromptTrialName, kPromptGroupName, params));
|
| +
|
| + base::FeatureList::ClearInstanceForTesting();
|
| + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
|
| + feature_list->RegisterFieldTrialOverride(
|
| + features::kBlockPromptsIfDismissedOften.name,
|
| + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
|
| + base::FeatureList::SetInstance(std::move(feature_list));
|
| + EXPECT_EQ(base::FeatureList::GetFieldTrial(
|
| + features::kBlockPromptsIfDismissedOften),
|
| + trial);
|
| +
|
| + std::map<std::string, std::string> actualParams;
|
| + EXPECT_TRUE(variations::GetVariationParamsByFeature(
|
| + features::kBlockPromptsIfDismissedOften, &actualParams));
|
| + EXPECT_EQ(params, actualParams);
|
| +
|
| + for (uint32_t i = 0; i < 5; ++i) {
|
| + TestPermissionContext permission_context(
|
| + profile(), content::PermissionType::MIDI_SYSEX,
|
| + CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
|
| +
|
| + ContentSetting expected =
|
| + (i < 4) ? CONTENT_SETTING_ASK : CONTENT_SETTING_BLOCK;
|
| + const PermissionRequestID id(
|
| + web_contents()->GetRenderProcessHost()->GetID(),
|
| + web_contents()->GetMainFrame()->GetRoutingID(), i);
|
| + permission_context.RequestPermission(
|
| + web_contents(), id, url, true /* user_gesture */,
|
| + base::Bind(&TestPermissionContext::TrackPermissionDecision,
|
| + base::Unretained(&permission_context)));
|
| +
|
| + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK);
|
| + EXPECT_EQ(1u, permission_context.decisions().size());
|
| + EXPECT_EQ(expected, permission_context.decisions()[0]);
|
| + EXPECT_TRUE(permission_context.tab_context_updated());
|
| + EXPECT_EQ(expected,
|
| + permission_context.GetContentSettingFromMap(url, url));
|
| + }
|
| +
|
| + // Ensure that we finish in the block state.
|
| + TestPermissionContext permission_context(
|
| + profile(), content::PermissionType::MIDI_SYSEX,
|
| + CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
|
| + EXPECT_EQ(CONTENT_SETTING_BLOCK,
|
| + permission_context.GetContentSettingFromMap(url, url));
|
| + base::FeatureList::ClearInstanceForTesting();
|
| + variations::testing::ClearAllVariationParams();
|
| + }
|
| +
|
| void TestRequestPermissionInvalidUrl(
|
| content::PermissionType permission_type,
|
| ContentSettingsType content_settings_type) {
|
| @@ -254,8 +437,8 @@ class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness {
|
| void TestGlobalPermissionsKillSwitch(
|
| content::PermissionType permission_type,
|
| ContentSettingsType content_settings_type) {
|
| - TestPermissionContext permission_context(profile(), permission_type,
|
| - content_settings_type);
|
| + TestKillSwitchPermissionContext permission_context(
|
| + profile(), permission_type, content_settings_type);
|
| permission_context.ResetFieldTrialList();
|
|
|
| EXPECT_FALSE(permission_context.IsPermissionKillSwitchOn());
|
| @@ -333,6 +516,18 @@ TEST_F(PermissionContextBaseTests, TestAskAndDismiss) {
|
| TestAskAndDismiss_TestContent();
|
| }
|
|
|
| +// Simulates clicking Dismiss (X) in the infobar/bubble with the block on too
|
| +// many dismissals feature active. The permission should be blocked after
|
| +// several dismissals.
|
| +TEST_F(PermissionContextBaseTests, TestDismissUntilBlocked) {
|
| + TestBlockOnSeveralDismissals_TestContent();
|
| +}
|
| +
|
| +// Test setting a custom number of dismissals before block via variations.
|
| +TEST_F(PermissionContextBaseTests, TestDismissVariations) {
|
| + TestVariationBlockOnSeveralDismissals_TestContent();
|
| +}
|
| +
|
| // Simulates non-valid requesting URL.
|
| // The permission should be denied but not saved for future use.
|
| TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
|
|
|