| // 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 "extensions/browser/api/declarative_net_request/prefs_helper.h" |
| |
| #include "components/crx_file/id_util.h" |
| #include "extensions/browser/api/declarative_net_request/constants.h" |
| #include "extensions/browser/api/declarative_net_request/utils.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extensions_test.h" |
| #include "extensions/buildflags/buildflags.h" |
| #include "extensions/common/extension_id.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); |
| |
| namespace extensions::declarative_net_request { |
| namespace { |
| |
| using ::testing::UnorderedElementsAre; |
| |
| class PrefsHelperTest : public ExtensionsTest { |
| public: |
| PrefsHelperTest() = default; |
| |
| // ExtensionsTest override. |
| void SetUp() override { |
| ExtensionsTest::SetUp(); |
| |
| prefs_ = ExtensionPrefs::Get(browser_context()); |
| ASSERT_TRUE(prefs_); |
| extension_id_ = crx_file::id_util::GenerateId("dummy_extension"); |
| } |
| |
| void TearDown() override { |
| // Drop unowned ref before destroying owning object in superclass. |
| prefs_ = nullptr; |
| ExtensionsTest::TearDown(); |
| } |
| |
| protected: |
| using RuleIdsToUpdate = PrefsHelper::RuleIdsToUpdate; |
| using UpdateDisabledStaticRulesResult = |
| PrefsHelper::UpdateDisabledStaticRulesResult; |
| using ExtensionId = extensions::ExtensionId; |
| |
| UpdateDisabledStaticRulesResult UpdateDisabledStaticRules( |
| RulesetID ruleset_id, |
| const RuleIdsToUpdate& ids_to_update) { |
| return PrefsHelper(*prefs_).UpdateDisabledStaticRules( |
| extension_id_, ruleset_id, ids_to_update); |
| } |
| |
| base::flat_set<int> GetDisabledRuleIds(RulesetID ruleset_id) const { |
| return PrefsHelper(*prefs_).GetDisabledStaticRuleIds( |
| extension_id_, ruleset_id); |
| } |
| |
| size_t GetDisabledRuleCount() const { |
| return PrefsHelper(*prefs_).GetDisabledStaticRuleCount(extension_id_); |
| } |
| |
| private: |
| raw_ptr<ExtensionPrefs> prefs_; |
| ExtensionId extension_id_; |
| }; |
| |
| TEST_F(PrefsHelperTest, UpdateStaticRulesTest) { |
| const RulesetID ruleset1(1); |
| const RulesetID ruleset2(2); |
| |
| // Set the disabled static rule limit as 7. |
| ScopedRuleLimitOverride scoped_disabled_static_rule_limit_override = |
| CreateScopedDisabledStaticRuleLimitOverrideForTesting(7); |
| |
| // The initial disabled rule ids set is empty. |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), testing::IsEmpty()); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), testing::IsEmpty()); |
| EXPECT_EQ(0u, GetDisabledRuleCount()); |
| |
| // Updating disabled rule ids with empty set doesn't make any change. |
| { |
| RuleIdsToUpdate ids_to_update(std::vector<int>() /* ids_to_disable */, |
| std::nullopt /* ids_to_enable */); |
| EXPECT_TRUE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset1, ids_to_update); |
| EXPECT_FALSE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), testing::IsEmpty()); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), testing::IsEmpty()); |
| EXPECT_EQ(0u, GetDisabledRuleCount()); |
| |
| // Disable rule 1, rule 2 and rule 3 of ruleset1. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::vector<int>({1, 2, 3}) /* ids_to_disable */, |
| std::nullopt /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset1, ids_to_update); |
| EXPECT_TRUE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, |
| UnorderedElementsAre(1, 2, 3)); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), testing::IsEmpty()); |
| EXPECT_EQ(3u, GetDisabledRuleCount()); |
| |
| // Disable rule 3, rule 4 and rule 5 of ruleset2. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::vector<int>({3, 4, 5}) /* ids_to_disable */, |
| std::nullopt /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_TRUE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, |
| UnorderedElementsAre(3, 4, 5)); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 4, 5)); |
| EXPECT_EQ(6u, GetDisabledRuleCount()); |
| |
| // Updating disabled rule ids with null set doesn't make any change. |
| { |
| RuleIdsToUpdate ids_to_update(std::nullopt /* ids_to_disable */, |
| std::nullopt /* ids_to_enable */); |
| EXPECT_TRUE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_FALSE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 4, 5)); |
| EXPECT_EQ(6u, GetDisabledRuleCount()); |
| |
| // Disable rule 4 and rule 5 of ruleset2 but it doesn't make any change since |
| // they are already disabled. Ignore enabling rule 5 since |ids_to_disable| |
| // takes priority over |ids_to_enable|. |
| { |
| RuleIdsToUpdate ids_to_update(std::vector<int>({4, 5}) /* ids_to_disable */, |
| std::vector<int>({5}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_FALSE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 4, 5)); |
| EXPECT_EQ(6u, GetDisabledRuleCount()); |
| |
| // Enable rule 4 and disable rule 5, rule 6 and rule 7 of ruleset2. Ignore |
| // enabling rule 5 since |ids_to_disable| takes priority over |ids_to_enable|. |
| // Disabling rule 5 doesn't make any change since rule 5 is already disabled. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::vector<int>({5, 6, 7}) /* ids_to_disable */, |
| std::vector<int>({4, 5}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_TRUE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, |
| UnorderedElementsAre(3, 5, 6, 7)); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 5, 6, 7)); |
| EXPECT_EQ(7u, GetDisabledRuleCount()); |
| |
| // Enable rule 1 and disable rule 3, rule 4 and rule 5 of ruleset2. Ignore |
| // enabling rule 3 since |ids_to_disable| takes priority over |ids_to_enable|. |
| // This operation fails since it exceeds the disabled static rule count limit. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::vector<int>({3, 4, 5}) /* ids_to_disable */, |
| std::vector<int>({1, 3}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset1, ids_to_update); |
| EXPECT_FALSE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(kDisabledStaticRuleCountExceeded, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), UnorderedElementsAre(1, 2, 3)); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 5, 6, 7)); |
| EXPECT_EQ(7u, GetDisabledRuleCount()); |
| |
| // Enable rule 1, rule 2 rule 3 and rule 4 of ruleset1. Enabling rule 4 |
| // doesn't make any change since rule 4 is not disabled. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::nullopt /* ids_to_disable */, |
| std::vector<int>({1, 2, 3, 4}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset1, ids_to_update); |
| EXPECT_TRUE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), testing::IsEmpty()); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), UnorderedElementsAre(3, 5, 6, 7)); |
| EXPECT_EQ(4u, GetDisabledRuleCount()); |
| |
| // Enable rule 3, rule 4, rule 5, rule 6 and rule 7 of ruleset2. Enabling |
| // rule 4 doesn't make any change since rule 4 is not disabled. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::nullopt /* ids_to_disable */, |
| std::vector<int>({3, 4, 5, 6, 7}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_TRUE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), testing::IsEmpty()); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), testing::IsEmpty()); |
| EXPECT_EQ(0u, GetDisabledRuleCount()); |
| |
| // Enable rule 3, rule 4 and rule 5 of ruleset2. It doesn't make any change |
| // since there is no disabled rules. |
| { |
| RuleIdsToUpdate ids_to_update( |
| std::nullopt /* ids_to_disable */, |
| std::vector<int>({3, 4, 5}) /* ids_to_enable */); |
| EXPECT_FALSE(ids_to_update.Empty()); |
| |
| auto result = UpdateDisabledStaticRules(ruleset2, ids_to_update); |
| EXPECT_FALSE(result.changed); |
| EXPECT_THAT(result.disabled_rule_ids_after_update, testing::IsEmpty()); |
| EXPECT_EQ(std::nullopt, result.error); |
| } |
| EXPECT_THAT(GetDisabledRuleIds(ruleset1), testing::IsEmpty()); |
| EXPECT_THAT(GetDisabledRuleIds(ruleset2), testing::IsEmpty()); |
| EXPECT_EQ(0u, GetDisabledRuleCount()); |
| } |
| |
| } // namespace |
| } // namespace extensions::declarative_net_request |