blob: d97167c028d582dcfa03d6284ccd60a76a0de5c7 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/content_settings/generated_notification_pref.h"
#include "base/ranges/algorithm.h"
#include "chrome/browser/content_settings/generated_permission_prompting_behavior_pref.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/api/settings_private/generated_pref_test_base.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/content_settings/core/test/content_settings_mock_provider.h"
#include "components/content_settings/core/test/content_settings_test_utils.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace settings_api = extensions::api::settings_private;
namespace settings_private = extensions::settings_private;
namespace content_settings {
namespace {
// Sets the value of |generated_pref| to |pref_value| and then ensures
// that the notification content settings and preferences match
// |expected_content_setting| and |expected_quieter_ui|. The value of
// the new PrefObject returned by the |generated_pref| is then checked
// against |pref_value|.
void ValidateGeneratedPrefSetting(
HostContentSettingsMap* map,
sync_preferences::TestingPrefServiceSyncable* prefs,
GeneratedNotificationPref* generated_pref,
SettingsState pref_value,
ContentSetting expected_content_setting,
bool expected_quieter_ui) {
EXPECT_EQ(
generated_pref->SetPref(
std::make_unique<base::Value>(static_cast<int>(pref_value)).get()),
settings_private::SetPrefResult::SUCCESS);
EXPECT_EQ(map->GetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS),
expected_content_setting);
EXPECT_EQ(prefs->GetUserPref(prefs::kEnableQuietNotificationPermissionUi)
->GetBool(),
expected_quieter_ui);
EXPECT_EQ(static_cast<SettingsState>(
generated_pref->GetPrefObject().value->GetInt()),
pref_value);
}
const SettingsState kNoRecommendedValue = static_cast<SettingsState>(-1);
// Represents a set of settings, preferences and the associated expected
// fields for the returned preference object.
struct NotificationSettingManagedTestCase {
ContentSetting default_content_setting;
content_settings::SettingSource default_content_setting_source;
settings_private::PrefSetting quieter_ui;
settings_private::PrefSource quieter_ui_source;
settings_api::ControlledBy expected_controlled_by;
settings_api::Enforcement expected_enforcement;
SettingsState expected_recommended_value;
std::vector<SettingsState> expected_user_selectable_values;
};
static const std::vector<NotificationSettingManagedTestCase> managed_test_cases{
{CONTENT_SETTING_ASK,
SettingSource::kUser,
settings_private::PrefSetting::kNotSet,
settings_private::PrefSource::kNone,
settings_api::ControlledBy::kNone,
settings_api::Enforcement::kNone,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_ASK,
SettingSource::kExtension,
settings_private::PrefSetting::kNotSet,
settings_private::PrefSource::kNone,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{SettingsState::kCanPromptWithAlwaysLoudUI,
SettingsState::kCanPromptWithAlwaysQuietUI}},
{CONTENT_SETTING_ASK,
SettingSource::kUser,
settings_private::PrefSetting::kEnforcedOn,
settings_private::PrefSource::kDevicePolicy,
settings_api::ControlledBy::kDevicePolicy,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{SettingsState::kCanPromptWithAlwaysQuietUI, SettingsState::kBlocked}},
{CONTENT_SETTING_ASK,
SettingSource::kUser,
settings_private::PrefSetting::kEnforcedOff,
settings_private::PrefSource::kExtension,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{SettingsState::kCanPromptWithAlwaysLoudUI, SettingsState::kBlocked}},
{CONTENT_SETTING_ASK,
SettingSource::kPolicy,
settings_private::PrefSetting::kEnforcedOn,
settings_private::PrefSource::kDevicePolicy,
settings_api::ControlledBy::kDevicePolicy,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_ASK,
SettingSource::kSupervised,
settings_private::PrefSetting::kRecommendedOn,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kChildRestriction,
settings_api::Enforcement::kEnforced,
SettingsState::kCanPromptWithAlwaysQuietUI,
{SettingsState::kCanPromptWithAlwaysLoudUI,
SettingsState::kCanPromptWithAlwaysQuietUI}},
{CONTENT_SETTING_ASK,
SettingSource::kExtension,
settings_private::PrefSetting::kRecommendedOff,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
SettingsState::kCanPromptWithAlwaysLoudUI,
{SettingsState::kCanPromptWithAlwaysLoudUI,
SettingsState::kCanPromptWithAlwaysQuietUI}},
{CONTENT_SETTING_BLOCK,
SettingSource::kExtension,
settings_private::PrefSetting::kRecommendedOn,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_BLOCK,
SettingSource::kExtension,
settings_private::PrefSetting::kRecommendedOff,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_BLOCK,
SettingSource::kExtension,
settings_private::PrefSetting::kEnforcedOn,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_BLOCK,
SettingSource::kExtension,
settings_private::PrefSetting::kEnforcedOff,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
{CONTENT_SETTING_BLOCK,
SettingSource::kExtension,
settings_private::PrefSetting::kNotSet,
settings_private::PrefSource::kRecommended,
settings_api::ControlledBy::kExtension,
settings_api::Enforcement::kEnforced,
kNoRecommendedValue,
{}},
};
void SetupManagedTestConditions(
HostContentSettingsMap* map,
sync_preferences::TestingPrefServiceSyncable* prefs,
const NotificationSettingManagedTestCase& test_case) {
auto provider = std::make_unique<content_settings::MockProvider>();
provider->SetWebsiteSetting(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
ContentSettingsType::NOTIFICATIONS,
base::Value(test_case.default_content_setting), /*constraints=*/{},
content_settings::PartitionKey::GetDefaultForTesting());
ProviderType provider_type;
switch (test_case.default_content_setting_source) {
case SettingSource::kPolicy:
provider_type = ProviderType::kPolicyProvider;
break;
case SettingSource::kExtension:
provider_type = ProviderType::kCustomExtensionProvider;
break;
case SettingSource::kSupervised:
provider_type = ProviderType::kSupervisedProvider;
break;
case SettingSource::kUser:
case SettingSource::kNone:
case SettingSource::kAllowList:
case SettingSource::kTpcdGrant:
case SettingSource::kInstalledWebApp:
provider_type = content_settings::ProviderType::kDefaultProvider;
}
content_settings::TestUtils::OverrideProvider(map, std::move(provider),
provider_type);
settings_private::SetPrefFromSource(
prefs, prefs::kEnableQuietNotificationPermissionUi, test_case.quieter_ui,
test_case.quieter_ui_source);
}
void ValidateManagedPreference(
settings_api::PrefObject& pref,
const NotificationSettingManagedTestCase& test_case) {
if (test_case.expected_controlled_by != settings_api::ControlledBy::kNone) {
EXPECT_EQ(pref.controlled_by, test_case.expected_controlled_by);
}
if (test_case.expected_enforcement != settings_api::Enforcement::kNone) {
EXPECT_EQ(pref.enforcement, test_case.expected_enforcement);
}
if (test_case.expected_recommended_value != kNoRecommendedValue) {
EXPECT_EQ(static_cast<SettingsState>(pref.recommended_value->GetInt()),
test_case.expected_recommended_value);
}
// Ensure user selectable values are as expected. Ordering is enforced here
// despite not being required by the SettingsPrivate API.
// First convert std::vector<std::unique_ptr<base::value(T)>> to
// std::vector<T> for easier comparison.
std::vector<SettingsState> pref_user_selectable_values;
if (pref.user_selectable_values) {
for (const auto& value : *pref.user_selectable_values) {
pref_user_selectable_values.push_back(
static_cast<SettingsState>(value.GetInt()));
}
}
EXPECT_TRUE(base::ranges::equal(pref_user_selectable_values,
test_case.expected_user_selectable_values));
}
} // namespace
typedef settings_private::GeneratedPrefTestBase GeneratedNotificationPrefTest;
TEST_F(GeneratedNotificationPrefTest, UpdatePreference) {
auto pref = std::make_unique<GeneratedNotificationPref>(profile());
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile());
// Setup a baseline content setting and preference state.
map->SetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS,
ContentSetting::CONTENT_SETTING_ASK);
prefs()->SetUserPref(prefs::kEnableQuietNotificationPermissionUi,
std::make_unique<base::Value>(false));
// Check that each of the three possible preference values sets the correct
// state and is correctly reflected in a newly returned PrefObject.
ValidateGeneratedPrefSetting(map, prefs(), pref.get(),
SettingsState::kBlocked,
ContentSetting::CONTENT_SETTING_BLOCK, false);
ValidateGeneratedPrefSetting(map, prefs(), pref.get(),
SettingsState::kCanPromptWithAlwaysLoudUI,
ContentSetting::CONTENT_SETTING_ASK, false);
ValidateGeneratedPrefSetting(map, prefs(), pref.get(),
SettingsState::kCanPromptWithAlwaysQuietUI,
ContentSetting::CONTENT_SETTING_ASK, true);
// Setting notification content setting to
// |ContentSetting::CONTENT_SETTING_BLOCK| should not change the quieter UI
// pref.
ValidateGeneratedPrefSetting(map, prefs(), pref.get(),
SettingsState::kBlocked,
ContentSetting::CONTENT_SETTING_BLOCK, true);
}
TEST_F(GeneratedNotificationPrefTest, UpdatePreferenceInvalidAction) {
auto pref = std::make_unique<GeneratedNotificationPref>(profile());
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile());
// Setup a baseline content setting and preference state.
map->SetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS,
ContentSetting::CONTENT_SETTING_BLOCK);
prefs()->SetUserPref(prefs::kEnableQuietNotificationPermissionUi,
std::make_unique<base::Value>(false));
// Confirm that a type mismatch is reported as such.
EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(true).get()),
settings_private::SetPrefResult::PREF_TYPE_MISMATCH);
// Check a numerical value outside of the acceptable range.
EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(
static_cast<int>(SettingsState::kBlocked) + 1)
.get()),
settings_private::SetPrefResult::PREF_TYPE_MISMATCH);
// Make quieter UI preference not user modifiable.
settings_private::SetPrefFromSource(
prefs(), prefs::kEnableQuietNotificationPermissionUi,
settings_private::PrefSetting::kEnforcedOff,
settings_private::PrefSource::kDevicePolicy);
// Confirm that quieter UI preference isn't modified when it's enforced.
EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(
static_cast<int>(
SettingsState::kCanPromptWithAlwaysQuietUI))
.get()),
settings_private::SetPrefResult::PREF_NOT_MODIFIABLE);
// Confirm the neither value was modified.
EXPECT_EQ(map->GetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS),
ContentSetting::CONTENT_SETTING_BLOCK);
EXPECT_FALSE(prefs()
->FindPreference(prefs::kEnableQuietNotificationPermissionUi)
->GetValue()
->GetBool());
// Make notification content setting not user modifiable.
auto provider = std::make_unique<content_settings::MockProvider>();
provider->SetWebsiteSetting(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
ContentSettingsType::NOTIFICATIONS,
base::Value(ContentSetting::CONTENT_SETTING_ASK), /*constraints=*/{},
content_settings::PartitionKey::GetDefaultForTesting());
content_settings::TestUtils::OverrideProvider(map, std::move(provider),
ProviderType::kPolicyProvider);
// Confirm that notification content setting isn't modified when it's
// enforced.
EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(
static_cast<int>(
SettingsState::kCanPromptWithAlwaysQuietUI))
.get()),
settings_private::SetPrefResult::PREF_NOT_MODIFIABLE);
// Confirm the neither value was modified.
EXPECT_EQ(map->GetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS),
ContentSetting::CONTENT_SETTING_ASK);
EXPECT_FALSE(prefs()
->FindPreference(prefs::kEnableQuietNotificationPermissionUi)
->GetValue()
->GetBool());
// Confirm that notification content setting isn't modified when it's
// enforced.
EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(
static_cast<int>(SettingsState::kBlocked))
.get()),
settings_private::SetPrefResult::PREF_NOT_MODIFIABLE);
// Confirm the neither value was modified.
EXPECT_EQ(map->GetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS),
ContentSetting::CONTENT_SETTING_ASK);
EXPECT_FALSE(prefs()
->FindPreference(prefs::kEnableQuietNotificationPermissionUi)
->GetValue()
->GetBool());
}
TEST_F(GeneratedNotificationPrefTest, NotifyPrefUpdates) {
// Update source Notification preferences and ensure an observer is fired.
auto pref = std::make_unique<GeneratedNotificationPref>(profile());
settings_private::TestGeneratedPrefObserver test_observer;
pref->AddObserver(&test_observer);
prefs()->SetUserPref(prefs::kEnableQuietNotificationPermissionUi,
std::make_unique<base::Value>(true));
EXPECT_EQ(test_observer.GetUpdatedPrefName(), kGeneratedNotificationPref);
test_observer.Reset();
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile());
map->SetDefaultContentSetting(ContentSettingsType::NOTIFICATIONS,
ContentSetting::CONTENT_SETTING_BLOCK);
EXPECT_EQ(test_observer.GetUpdatedPrefName(), kGeneratedNotificationPref);
}
TEST_F(GeneratedNotificationPrefTest, ManagedState) {
for (const auto& test_case : managed_test_cases) {
TestingProfile profile;
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(&profile);
testing::Message scope_message;
scope_message << "Content Setting:" << test_case.default_content_setting
<< " Quieter UI:" << static_cast<int>(test_case.quieter_ui);
SCOPED_TRACE(scope_message);
SetupManagedTestConditions(map, profile.GetTestingPrefService(), test_case);
auto pref =
std::make_unique<content_settings::GeneratedNotificationPref>(&profile);
auto pref_object = pref->GetPrefObject();
ValidateManagedPreference(pref_object, test_case);
}
}
} // namespace content_settings