blob: 2c1dac6feb2df8055ff779c90110bf5d93fcc2e2 [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/ui/extensions/extension_settings_overridden_dialog.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_base.h"
#include "chrome/browser/ui/ui_features.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/uninstall_reason.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/manifest.h"
#include "extensions/common/value_builder.h"
namespace {
using DialogResult = SettingsOverriddenDialogController::DialogResult;
constexpr char kTestAcknowledgedPreference[] = "TestPreference";
constexpr char kTestDialogResultHistogramName[] = "TestHistogramName";
ExtensionSettingsOverriddenDialog::Params CreateTestDialogParams(
const extensions::ExtensionId& controlling_id) {
return {controlling_id,
kTestAcknowledgedPreference,
kTestDialogResultHistogramName,
u"Test Dialog Title",
u"Test Dialog Body",
nullptr};
}
} // namespace
class ExtensionSettingsOverriddenDialogUnitTest
: public extensions::ExtensionServiceTestBase {
public:
void SetUp() override {
extensions::ExtensionServiceTestBase::SetUp();
InitializeEmptyExtensionService();
}
// Adds a new extension with the given `name` and `location` to the profile.
// If `include_extra_perms` is true, this also adds a simple permission to
// the extension (so that it's not considered a "simple override").
const extensions::Extension* AddExtension(
const char* name = "alpha",
extensions::mojom::ManifestLocation location =
extensions::mojom::ManifestLocation::kInternal,
bool include_extra_perms = true) {
extensions::ExtensionBuilder builder(name);
builder.SetLocation(location);
if (include_extra_perms)
builder.AddPermission("storage");
scoped_refptr<const extensions::Extension> extension = builder.Build();
service()->AddExtension(extension.get());
return extension.get();
}
extensions::ExtensionPrefs* GetExtensionPrefs() {
return extensions::ExtensionPrefs::Get(profile());
}
// Returns true if the extension with the given |id| has been marked as
// acknowledged.
bool IsExtensionAcknowledged(const extensions::ExtensionId& id) {
bool acknowledged = false;
return GetExtensionPrefs()->ReadPrefAsBoolean(
id, kTestAcknowledgedPreference, &acknowledged) &&
acknowledged;
}
};
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
ShouldShowWithAControllingExtension) {
const extensions::Extension* extension = AddExtension("fancy extension");
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
ExtensionSettingsOverriddenDialog::ShowParams show_params =
controller.GetShowParams();
EXPECT_EQ(u"Test Dialog Title", show_params.dialog_title);
EXPECT_EQ(u"Test Dialog Body", show_params.message);
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
WontShowForAnAcknowledgedExtension) {
const extensions::Extension* extension = AddExtension();
GetExtensionPrefs()->UpdateExtensionPref(extension->id(),
kTestAcknowledgedPreference,
std::make_unique<base::Value>(true));
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_FALSE(controller.ShouldShow());
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
WontShowForAnExtensionThatCantBeDisabled) {
const extensions::Extension* policy_extension = AddExtension(
"policy installed",
extensions::mojom::ManifestLocation::kExternalPolicyDownload);
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(policy_extension->id()), profile());
EXPECT_FALSE(controller.ShouldShow());
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
ExtensionDisabledOnDialogRejection) {
base::HistogramTester histogram_tester;
const extensions::Extension* extension = AddExtension();
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kChangeSettingsBack);
histogram_tester.ExpectUniqueSample(kTestDialogResultHistogramName,
DialogResult::kChangeSettingsBack, 1);
EXPECT_TRUE(registry()->disabled_extensions().Contains(extension->id()));
EXPECT_EQ(extensions::disable_reason::DISABLE_USER_ACTION,
GetExtensionPrefs()->GetDisableReasons(extension->id()));
EXPECT_FALSE(IsExtensionAcknowledged(extension->id()));
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
ExtensionAcknowledgedOnDialogAcceptance) {
base::HistogramTester histogram_tester;
const extensions::Extension* extension = AddExtension();
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kKeepNewSettings);
histogram_tester.ExpectUniqueSample(kTestDialogResultHistogramName,
DialogResult::kKeepNewSettings, 1);
EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
EXPECT_TRUE(IsExtensionAcknowledged(extension->id()));
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
ExtensionIsNeitherDisabledNorAcknowledgedOnDialogDismissal) {
base::HistogramTester histogram_tester;
const extensions::Extension* extension = AddExtension();
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kDialogDismissed);
histogram_tester.ExpectUniqueSample(kTestDialogResultHistogramName,
DialogResult::kDialogDismissed, 1);
EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
EXPECT_FALSE(IsExtensionAcknowledged(extension->id()));
}
TEST_F(
ExtensionSettingsOverriddenDialogUnitTest,
ExtensionIsNeitherDisabledNorAcknowledgedOnDialogCloseWithoutUserAction) {
base::HistogramTester histogram_tester;
const extensions::Extension* extension = AddExtension();
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kDialogClosedWithoutUserAction);
histogram_tester.ExpectUniqueSample(
kTestDialogResultHistogramName,
DialogResult::kDialogClosedWithoutUserAction, 1);
EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
EXPECT_FALSE(IsExtensionAcknowledged(extension->id()));
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
WontShowTwiceForTheSameExtensionInTheSameSession) {
const extensions::Extension* extension = AddExtension();
{
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kDialogDismissed);
}
{
// Since the dialog was already shown for this extension, it should not
// display a second time.
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_FALSE(controller.ShouldShow());
}
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
CanShowForDifferentExtensionsInTheSameSession) {
const extensions::Extension* extension_one = AddExtension("one");
{
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension_one->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
controller.OnDialogShown();
controller.HandleDialogResult(DialogResult::kDialogDismissed);
}
const extensions::Extension* extension_two = AddExtension("two");
{
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension_two->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
}
}
TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
ExtensionRemovedWhileDialogShown) {
const extensions::Extension* extension = AddExtension();
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
EXPECT_TRUE(controller.ShouldShow());
controller.OnDialogShown();
service()->UninstallExtension(
extension->id(), extensions::UNINSTALL_REASON_FOR_TESTING, nullptr);
controller.HandleDialogResult(DialogResult::kChangeSettingsBack);
}
class LightweightExtensionSettingsOverriddenDialogTest
: public ExtensionSettingsOverriddenDialogUnitTest,
public testing::WithParamInterface<bool> {
public:
LightweightExtensionSettingsOverriddenDialogTest() {
if (GetParam()) {
feature_list_.InitAndEnableFeature(
features::kLightweightExtensionOverrideConfirmations);
} else {
feature_list_.InitAndDisableFeature(
features::kLightweightExtensionOverrideConfirmations);
}
}
private:
base::test::ScopedFeatureList feature_list_;
};
INSTANTIATE_TEST_SUITE_P(All,
LightweightExtensionSettingsOverriddenDialogTest,
testing::Bool());
// Tests that simple override extensions don't trigger the settings overridden
// dialog if the lightweight extension overrides experiment is enabled.
TEST_P(LightweightExtensionSettingsOverriddenDialogTest,
SimpleOverrideExtensionDoesntTriggerDialog) {
const extensions::Extension* extension =
AddExtension("alpha", extensions::mojom::ManifestLocation::kInternal,
/*include_extra_perms=*/false);
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
// The dialog should *not* want to show if the feature is enabled.
bool expect_should_show = !GetParam();
EXPECT_EQ(expect_should_show, controller.ShouldShow());
// Regardless of features enablement, the the extension should not be
// acknowledged. The latter is important to re-assess the extension in case
// it updates.
EXPECT_FALSE(IsExtensionAcknowledged(extension->id()));
}
// Tests that simple override extensions don't trigger the settings overridden
// dialog if the lightweight extension overrides experiment is enabled.
TEST_P(LightweightExtensionSettingsOverriddenDialogTest,
NonSimpleOverrideExtensionAlwaysTriggersDialog) {
const extensions::Extension* extension =
AddExtension("alpha", extensions::mojom::ManifestLocation::kInternal,
/*include_extra_perms=*/true);
ExtensionSettingsOverriddenDialog controller(
CreateTestDialogParams(extension->id()), profile());
// The dialog should always show, regardless of feature state.
EXPECT_TRUE(controller.ShouldShow());
}