diff options
Diffstat (limited to 'chromium/components/policy/core/common/policy_map_unittest.cc')
-rw-r--r-- | chromium/components/policy/core/common/policy_map_unittest.cc | 1807 |
1 files changed, 1807 insertions, 0 deletions
diff --git a/chromium/components/policy/core/common/policy_map_unittest.cc b/chromium/components/policy/core/common/policy_map_unittest.cc new file mode 100644 index 00000000000..6501adf495b --- /dev/null +++ b/chromium/components/policy/core/common/policy_map_unittest.cc @@ -0,0 +1,1807 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/policy/core/common/policy_map.h" + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "components/policy/core/common/external_data_manager.h" +#include "components/policy/core/common/policy_merger.h" +#include "components/policy/core/common/policy_types.h" +#include "components/policy/policy_constants.h" +#include "components/strings/grit/components_strings.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace policy { + +namespace { + +// Dummy policy names. +const char kTestPolicyName1[] = "policy.test.1"; +const char kTestPolicyName2[] = "policy.test.2"; +const char kTestPolicyName3[] = "policy.test.3"; +const char kTestPolicyName4[] = "policy.test.4"; +const char kTestPolicyName5[] = "policy.test.5"; +const char kTestPolicyName6[] = "policy.test.6"; +const char kTestPolicyName7[] = "policy.test.7"; +const char kTestPolicyName8[] = "policy.test.8"; + +// Dummy error message. +const char16_t kTestError[] = u"Test error message"; + +// Utility functions for the tests. +void SetPolicy(PolicyMap* map, const char* name, base::Value value) { + map->Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + std::move(value), nullptr); +} + +void SetPolicy(PolicyMap* map, + const char* name, + std::unique_ptr<ExternalDataFetcher> external_data_fetcher) { + map->Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + absl::nullopt, std::move(external_data_fetcher)); +} + +template <class T> +std::vector<base::Value> GetListStorage(const std::vector<T> entry) { + std::vector<base::Value> result; + for (const auto& it : entry) + result.emplace_back(base::Value(it)); + return result; +} + +} // namespace + +class PolicyMapTestBase { + protected: + std::unique_ptr<ExternalDataFetcher> CreateExternalDataFetcher( + const std::string& policy) const; +}; + +std::unique_ptr<ExternalDataFetcher> +PolicyMapTestBase::CreateExternalDataFetcher(const std::string& policy) const { + return std::make_unique<ExternalDataFetcher>( + base::WeakPtr<ExternalDataManager>(), policy); +} + +class PolicyMapTest : public PolicyMapTestBase, public testing::Test {}; + +TEST_F(PolicyMapTest, SetAndGet) { + PolicyMap map; + EXPECT_FALSE(map.IsPolicySet(kTestPolicyName1)); + SetPolicy(&map, kTestPolicyName1, base::Value("aaa")); + EXPECT_TRUE(map.IsPolicySet(kTestPolicyName1)); + const base::Value kExpectedStringA("aaa"); + EXPECT_EQ(kExpectedStringA, *map.GetValueUnsafe(kTestPolicyName1)); + EXPECT_EQ(kExpectedStringA, + *map.GetValue(kTestPolicyName1, base::Value::Type::STRING)); + EXPECT_EQ(nullptr, + map.GetValue(kTestPolicyName1, base::Value::Type::BOOLEAN)); + + SetPolicy(&map, kTestPolicyName1, base::Value("bbb")); + EXPECT_TRUE(map.IsPolicySet(kTestPolicyName1)); + const base::Value kExpectedStringB("bbb"); + EXPECT_EQ(kExpectedStringB, *map.GetValueUnsafe(kTestPolicyName1)); + EXPECT_EQ(kExpectedStringB, + *map.GetValue(kTestPolicyName1, base::Value::Type::STRING)); + EXPECT_EQ(nullptr, + map.GetValue(kTestPolicyName1, base::Value::Type::BOOLEAN)); + + SetPolicy(&map, kTestPolicyName1, base::Value(true)); + EXPECT_TRUE(map.IsPolicySet(kTestPolicyName1)); + const base::Value kExpectedBool(true); + EXPECT_EQ(kExpectedBool, *map.GetValueUnsafe(kTestPolicyName1)); + EXPECT_EQ(nullptr, map.GetValue(kTestPolicyName1, base::Value::Type::STRING)); + EXPECT_EQ(kExpectedBool, + *map.GetValue(kTestPolicyName1, base::Value::Type::BOOLEAN)); + + SetPolicy(&map, kTestPolicyName1, CreateExternalDataFetcher("dummy")); + EXPECT_FALSE(map.IsPolicySet(kTestPolicyName1)); + map.AddMessage(kTestPolicyName1, PolicyMap::MessageType::kError, + IDS_POLICY_STORE_STATUS_VALIDATION_ERROR, {kTestError}); + EXPECT_EQ(nullptr, map.GetValueUnsafe(kTestPolicyName1)); + const PolicyMap::Entry* entry = map.Get(kTestPolicyName1); + ASSERT_NE(nullptr, entry); + EXPECT_EQ(POLICY_LEVEL_MANDATORY, entry->level); + EXPECT_EQ(POLICY_SCOPE_USER, entry->scope); + EXPECT_EQ(POLICY_SOURCE_CLOUD, entry->source); + std::u16string error_string = + base::StrCat({u"Validation error: ", kTestError}); + PolicyMap::Entry::L10nLookupFunction lookup = base::BindRepeating( + static_cast<std::u16string (*)(int)>(&base::NumberToString16)); + EXPECT_EQ(error_string, entry->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_TRUE( + ExternalDataFetcher::Equals(entry->external_data_fetcher.get(), + CreateExternalDataFetcher("dummy").get())); + map.Set(kTestPolicyName1, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, absl::nullopt, nullptr); + EXPECT_FALSE(map.IsPolicySet(kTestPolicyName1)); + EXPECT_EQ(nullptr, map.GetValueUnsafe(kTestPolicyName1)); + entry = map.Get(kTestPolicyName1); + ASSERT_NE(nullptr, entry); + EXPECT_EQ(POLICY_LEVEL_RECOMMENDED, entry->level); + EXPECT_EQ(POLICY_SCOPE_MACHINE, entry->scope); + EXPECT_EQ(POLICY_SOURCE_ENTERPRISE_DEFAULT, entry->source); + EXPECT_EQ(std::u16string(), entry->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_FALSE(entry->external_data_fetcher); +} + +TEST_F(PolicyMapTest, AddMessage_Error) { + PolicyMap map; + SetPolicy(&map, kTestPolicyName1, base::Value(0)); + PolicyMap::Entry* entry1 = map.GetMutable(kTestPolicyName1); + PolicyMap::Entry::L10nLookupFunction lookup = base::BindRepeating( + static_cast<std::u16string (*)(int)>(&base::NumberToString16)); + EXPECT_EQ(std::u16string(), entry1->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + map.AddMessage(kTestPolicyName1, PolicyMap::MessageType::kError, 1234); + EXPECT_EQ(u"1234", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + map.AddMessage(kTestPolicyName1, PolicyMap::MessageType::kError, 5678); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + + // Add second entry to make sure errors are added individually. + SetPolicy(&map, kTestPolicyName2, base::Value(0)); + PolicyMap::Entry* entry2 = map.GetMutable(kTestPolicyName2); + // Test adding Error message with placeholder replacement (one arg) + map.AddMessage(kTestPolicyName2, PolicyMap::MessageType::kError, + IDS_POLICY_MIGRATED_OLD_POLICY, {u"SomeNewPolicy"}); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_EQ( + u"This policy is deprecated. You should use the " + u"SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kError, lookup)); + map.AddMessage(kTestPolicyName2, PolicyMap::MessageType::kError, 1357); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kError, lookup)); + // Test adding Error message with placeholder replacement (two args) + map.AddMessage(kTestPolicyName1, PolicyMap::MessageType::kError, + IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, + {u"SomeSource", u"SomeDestination"}); + EXPECT_EQ( + u"1234\n5678\nSharing from SomeSource to SomeDestination has " + u"been blocked by administrator policy", + entry1->GetLocalizedMessages(PolicyMap::MessageType::kError, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kError, lookup)); + + // Ensure other message types are empty + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); +} + +TEST_F(PolicyMapTest, AddMessage_Warning) { + PolicyMap map; + SetPolicy(&map, kTestPolicyName1, base::Value(0)); + PolicyMap::Entry* entry1 = map.GetMutable(kTestPolicyName1); + PolicyMap::Entry::L10nLookupFunction lookup = base::BindRepeating( + static_cast<std::u16string (*)(int)>(&base::NumberToString16)); + EXPECT_EQ(std::u16string(), entry1->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + entry1->AddMessage(PolicyMap::MessageType::kWarning, 1234); + EXPECT_EQ(u"1234", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + entry1->AddMessage(PolicyMap::MessageType::kWarning, 5678); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + + // Add second entry to make sure warnings are added individually. + SetPolicy(&map, kTestPolicyName2, base::Value(0)); + PolicyMap::Entry* entry2 = map.GetMutable(kTestPolicyName2); + // Test adding Warning message with placeholder replacement (one arg) + entry2->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_MIGRATED_OLD_POLICY, {u"SomeNewPolicy"}); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + EXPECT_EQ( + u"This policy is deprecated. You should use the " + u"SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kWarning, lookup)); + entry2->AddMessage(PolicyMap::MessageType::kWarning, 1357); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kWarning, lookup)); + // Test adding Warning message with placeholder replacement (two args) + entry1->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, + {u"SomeSource", u"SomeDestination"}); + EXPECT_EQ( + u"1234\n5678\nSharing from SomeSource to SomeDestination has " + u"been blocked by administrator policy", + entry1->GetLocalizedMessages(PolicyMap::MessageType::kWarning, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kWarning, lookup)); + + // Ensure other message types are empty + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); +} + +TEST_F(PolicyMapTest, AddMessage_Info) { + PolicyMap map; + SetPolicy(&map, kTestPolicyName1, base::Value(0)); + PolicyMap::Entry* entry1 = map.GetMutable(kTestPolicyName1); + PolicyMap::Entry::L10nLookupFunction lookup = base::BindRepeating( + static_cast<std::u16string (*)(int)>(&base::NumberToString16)); + EXPECT_EQ(std::u16string(), entry1->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); + entry1->AddMessage(PolicyMap::MessageType::kInfo, 1234); + EXPECT_EQ(u"1234", entry1->GetLocalizedMessages(PolicyMap::MessageType::kInfo, + lookup)); + entry1->AddMessage(PolicyMap::MessageType::kInfo, 5678); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); + + // Add second entry to make sure messages are added individually. + SetPolicy(&map, kTestPolicyName2, base::Value(0)); + PolicyMap::Entry* entry2 = map.GetMutable(kTestPolicyName2); + // Test adding Info message with placeholder replacement (one arg) + entry2->AddMessage(PolicyMap::MessageType::kInfo, + IDS_POLICY_MIGRATED_OLD_POLICY, {u"SomeNewPolicy"}); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); + EXPECT_EQ( + u"This policy is deprecated. You should use the " + u"SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kInfo, lookup)); + entry2->AddMessage(PolicyMap::MessageType::kInfo, 1357); + EXPECT_EQ(u"1234\n5678", entry1->GetLocalizedMessages( + PolicyMap::MessageType::kInfo, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kInfo, lookup)); + // Test adding Info message with placeholder replacement (two args) + entry1->AddMessage(PolicyMap::MessageType::kInfo, + IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, + {u"SomeSource", u"SomeDestination"}); + EXPECT_EQ( + u"1234\n5678\nSharing from SomeSource to SomeDestination has " + u"been blocked by administrator policy", + entry1->GetLocalizedMessages(PolicyMap::MessageType::kInfo, lookup)); + EXPECT_EQ( + u"1357\nThis policy is deprecated. You should use " + u"the SomeNewPolicy policy instead.", + entry2->GetLocalizedMessages(PolicyMap::MessageType::kInfo, lookup)); + + // Ensure other message types are empty + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kError, lookup)); + EXPECT_EQ(std::u16string(), entry2->GetLocalizedMessages( + PolicyMap::MessageType::kWarning, lookup)); +} + +TEST_F(PolicyMapTest, Equals) { + PolicyMap a; + SetPolicy(&a, kTestPolicyName1, base::Value("aaa")); + PolicyMap a2; + SetPolicy(&a2, kTestPolicyName1, base::Value("aaa")); + PolicyMap b; + SetPolicy(&b, kTestPolicyName1, base::Value("bbb")); + PolicyMap c; + SetPolicy(&c, kTestPolicyName1, base::Value("aaa")); + SetPolicy(&c, kTestPolicyName2, base::Value(true)); + PolicyMap d; + SetPolicy(&d, kTestPolicyName1, CreateExternalDataFetcher("ddd")); + PolicyMap d2; + SetPolicy(&d2, kTestPolicyName1, CreateExternalDataFetcher("ddd")); + PolicyMap e; + SetPolicy(&e, kTestPolicyName1, CreateExternalDataFetcher("eee")); + EXPECT_FALSE(a.Equals(b)); + EXPECT_FALSE(a.Equals(c)); + EXPECT_FALSE(a.Equals(d)); + EXPECT_FALSE(a.Equals(e)); + EXPECT_FALSE(b.Equals(a)); + EXPECT_FALSE(b.Equals(c)); + EXPECT_FALSE(b.Equals(d)); + EXPECT_FALSE(b.Equals(e)); + EXPECT_FALSE(c.Equals(a)); + EXPECT_FALSE(c.Equals(b)); + EXPECT_FALSE(c.Equals(d)); + EXPECT_FALSE(c.Equals(e)); + EXPECT_FALSE(d.Equals(a)); + EXPECT_FALSE(d.Equals(b)); + EXPECT_FALSE(d.Equals(c)); + EXPECT_FALSE(d.Equals(e)); + EXPECT_FALSE(e.Equals(a)); + EXPECT_FALSE(e.Equals(b)); + EXPECT_FALSE(e.Equals(c)); + EXPECT_FALSE(e.Equals(d)); + EXPECT_TRUE(a.Equals(a2)); + EXPECT_TRUE(a2.Equals(a)); + EXPECT_TRUE(d.Equals(d2)); + EXPECT_TRUE(d2.Equals(d)); + PolicyMap empty1; + PolicyMap empty2; + EXPECT_TRUE(empty1.Equals(empty2)); + EXPECT_TRUE(empty2.Equals(empty1)); + EXPECT_FALSE(empty1.Equals(a)); + EXPECT_FALSE(a.Equals(empty1)); +} + +TEST_F(PolicyMapTest, Swap) { + PolicyMap a; + SetPolicy(&a, kTestPolicyName1, base::Value("aaa")); + SetPolicy(&a, kTestPolicyName2, CreateExternalDataFetcher("dummy")); + PolicyMap b; + SetPolicy(&b, kTestPolicyName1, base::Value("bbb")); + SetPolicy(&b, kTestPolicyName3, base::Value(true)); + + a.Swap(&b); + const base::Value kExpectedStringB("bbb"); + EXPECT_EQ(kExpectedStringB, + *a.GetValue(kTestPolicyName1, base::Value::Type::STRING)); + const base::Value kExpectedBool(true); + EXPECT_EQ(kExpectedBool, + *a.GetValue(kTestPolicyName3, base::Value::Type::BOOLEAN)); + EXPECT_EQ(nullptr, a.GetValueUnsafe(kTestPolicyName2)); + EXPECT_EQ(nullptr, a.Get(kTestPolicyName2)); + const base::Value kExpectedStringA("aaa"); + EXPECT_EQ(kExpectedStringA, + *b.GetValue(kTestPolicyName1, base::Value::Type::STRING)); + EXPECT_EQ(nullptr, b.GetValueUnsafe(kTestPolicyName3)); + EXPECT_EQ(nullptr, a.GetValueUnsafe(kTestPolicyName2)); + const PolicyMap::Entry* entry = b.Get(kTestPolicyName2); + ASSERT_TRUE(entry); + EXPECT_TRUE( + ExternalDataFetcher::Equals(CreateExternalDataFetcher("dummy").get(), + entry->external_data_fetcher.get())); + + b.Clear(); + a.Swap(&b); + PolicyMap empty; + EXPECT_TRUE(a.Equals(empty)); + EXPECT_FALSE(b.Equals(empty)); +} + +#if !BUILDFLAG(IS_CHROMEOS) +// Policy precedence changes are not supported on Chrome OS. +TEST_F(PolicyMapTest, MergeFrom_CloudMetapolicies) { + // The two precedence metapolicies, CloudPolicyOverridesPlatformPolicy and + // CloudUserPolicyOverridesCloudMachinePolicy, are set as cloud policies in + // the incoming |policy_map_2|. + PolicyMap policy_map_1; + policy_map_1.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value("platform_machine"), nullptr); + policy_map_1.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("cloud_user"), nullptr); + policy_map_1.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("cloud_user"), nullptr); + policy_map_1.Set(kTestPolicyName4, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("cloud_machine"), nullptr); + + PolicyMap policy_map_2; + // Set matching user and device affiliation IDs to allow cloud user policies + // to take precedence over cloud machine policies. + base::flat_set<std::string> affiliation_ids; + affiliation_ids.insert("a"); + policy_map_2.SetUserAffiliationIds(affiliation_ids); + policy_map_2.SetDeviceAffiliationIds(affiliation_ids); + + policy_map_2.Set(key::kCloudPolicyOverridesPlatformPolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + policy_map_2.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + policy_map_2.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("cloud_machine"), nullptr); + policy_map_2.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value("platform_user"), + nullptr); + policy_map_2.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value("platform_machine"), nullptr); + policy_map_2.Set(kTestPolicyName4, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("cloud_user"), nullptr); + + auto conflicting_policy_1 = policy_map_1.Get(kTestPolicyName1)->DeepCopy(); + auto conflicting_policy_2 = policy_map_2.Get(kTestPolicyName2)->DeepCopy(); + auto conflicting_policy_3 = policy_map_2.Get(kTestPolicyName3)->DeepCopy(); + auto conflicting_policy_4 = policy_map_1.Get(kTestPolicyName4)->DeepCopy(); + + policy_map_1.MergeFrom(policy_map_2); + + PolicyMap policy_map_expected; + + policy_map_expected.SetUserAffiliationIds(affiliation_ids); + policy_map_expected.SetDeviceAffiliationIds(affiliation_ids); + policy_map_expected.Set(key::kCloudPolicyOverridesPlatformPolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + policy_map_expected.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + // Cloud machine overrides platform machine. + policy_map_expected.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("cloud_machine"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddConflictingPolicy(std::move(conflicting_policy_1)); + // Cloud user overrides platform user. + policy_map_expected.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("cloud_user"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName2) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName2) + ->AddConflictingPolicy(std::move(conflicting_policy_2)); + // Cloud user overrides platform machine. + policy_map_expected.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("cloud_user"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName3) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName3) + ->AddConflictingPolicy(std::move(conflicting_policy_3)); + // Cloud user overrides cloud machine. + policy_map_expected.Set(kTestPolicyName4, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("cloud_user"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName4) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName4) + ->AddConflictingPolicy(std::move(conflicting_policy_4)); + + EXPECT_TRUE(policy_map_1.Equals(policy_map_expected)); +} +#endif // BUILDFLAG(IS_CHROMEOS) + +TEST_F(PolicyMapTest, MergeValuesList) { + std::vector<base::Value> abcd = + GetListStorage<std::string>({"a", "b", "c", "d"}); + std::vector<base::Value> abc = GetListStorage<std::string>({"a", "b", "c"}); + std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"}); + std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"}); + std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"}); + + std::vector<base::Value> int12 = GetListStorage<int>({1, 2}); + std::vector<base::Value> int34 = GetListStorage<int>({3, 4}); + std::vector<base::Value> int56 = GetListStorage<int>({5, 6}); + std::vector<base::Value> int1234 = GetListStorage<int>({1, 2, 3, 4}); + + base::Value dict_ab(base::Value::Type::DICTIONARY); + dict_ab.SetBoolKey("a", true); + dict_ab.SetBoolKey("b", false); + base::Value dict_c(base::Value::Type::DICTIONARY); + dict_c.SetBoolKey("c", false); + base::Value dict_d(base::Value::Type::DICTIONARY); + dict_d.SetBoolKey("d", false); + + std::vector<base::Value> list_dict_abd; + list_dict_abd.emplace_back(dict_ab.Clone()); + list_dict_abd.emplace_back(dict_d.Clone()); + std::vector<base::Value> list_dict_c; + list_dict_c.emplace_back(dict_c.Clone()); + + std::vector<base::Value> list_dict_abcd; + list_dict_abcd.emplace_back(dict_ab.Clone()); + list_dict_abcd.emplace_back(dict_d.Clone()); + list_dict_abcd.emplace_back(dict_c.Clone()); + + // Case 1 - kTestPolicyName1 + // Enterprise default policies should not be merged with other sources. + PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value(abc), nullptr); + + case1.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_COMMAND_LINE, base::Value(cd), nullptr)); + + case1.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr)); + + case1.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr)); + + PolicyMap::Entry expected_case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, base::Value(abcd), + nullptr); + expected_case1.AddConflictingPolicy(case1.DeepCopy()); + + // Case 2 - kTestPolicyName2 + // Policies should only be merged with other policies with the same target, + // level and scope. + PolicyMap::Entry case2(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(int12), nullptr); + + case2.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value(int34), nullptr)); + + case2.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(int56), nullptr)); + + PolicyMap::Entry expected_case2(POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, + base::Value(int1234), nullptr); + expected_case2.AddConflictingPolicy(case2.DeepCopy()); + + // Case 3 - kTestPolicyName3 + // Trivial case with 2 sources. + PolicyMap::Entry case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(ab), nullptr); + + case3.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr)); + + PolicyMap::Entry expected_case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, base::Value(abcd), + nullptr); + auto case3_blocked_by_group = expected_case3.DeepCopy(); + case3_blocked_by_group.SetIgnoredByPolicyAtomicGroup(); + expected_case3.AddConflictingPolicy(case3.DeepCopy()); + + // Case 4 - kTestPolicyName4 + // Policies with a single source should stay the same. + PolicyMap::Entry case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(ef), nullptr); + PolicyMap::Entry expected_case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, base::Value(ef), + nullptr); + expected_case4.AddConflictingPolicy(case4.DeepCopy()); + + // Case 5 - kTestPolicyName5 + // Policies that are not lists should not be merged. + // If such a policy is explicitly in the list of policies to merge, an error + // is added to the entry and the policy stays intact. + PolicyMap::Entry case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value("bad stuff"), + nullptr); + + PolicyMap::Entry expected_case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, + base::Value("bad stuff"), nullptr); + expected_case5.AddMessage( + PolicyMap::MessageType::kError, + IDS_POLICY_LIST_MERGING_WRONG_POLICY_TYPE_SPECIFIED); + + // Case 6 - kTestPolicyName6 + // User cloud policies should not be merged with other sources. + PolicyMap::Entry case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr); + case6.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(cd), nullptr)); + case6.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(ef), nullptr)); + PolicyMap::Entry expected_case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, base::Value(ab), + nullptr); + expected_case6.AddConflictingPolicy(case6.DeepCopy()); + + // Case 7 - kTestPolicyName7 + // User platform policies should not be merged under any circumstances. + PolicyMap::Entry case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(cd), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_COMMAND_LINE, base::Value(ef), nullptr)); + PolicyMap::Entry expected_case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, base::Value(ab), + nullptr); + expected_case7.AddConflictingPolicy(case7.DeepCopy()); + + // Case 8 - kTestPolicyName8 + // Lists of dictionaries should not have duplicates. + PolicyMap::Entry case8(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value(list_dict_abd), + nullptr); + + case8.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value(list_dict_abd), nullptr)); + + case8.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_COMMAND_LINE, + base::Value(list_dict_c), nullptr)); + + PolicyMap::Entry expected_case8(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, + base::Value(list_dict_abcd), nullptr); + expected_case8.AddConflictingPolicy(case8.DeepCopy()); + + PolicyMap policy_not_merged; + policy_not_merged.Set(kTestPolicyName1, case1.DeepCopy()); + policy_not_merged.Set(kTestPolicyName2, case2.DeepCopy()); + policy_not_merged.Set(kTestPolicyName3, case3.DeepCopy()); + policy_not_merged.Set(kTestPolicyName4, case4.DeepCopy()); + policy_not_merged.Set(kTestPolicyName5, case5.DeepCopy()); + policy_not_merged.Set(kTestPolicyName6, case6.DeepCopy()); + policy_not_merged.Set(kTestPolicyName7, case7.DeepCopy()); + policy_not_merged.Set(kTestPolicyName8, case8.DeepCopy()); + + PolicyMap expected_list_merged; + expected_list_merged.Set(kTestPolicyName1, expected_case1.DeepCopy()); + expected_list_merged.Set(kTestPolicyName2, expected_case2.DeepCopy()); + expected_list_merged.Set(kTestPolicyName3, expected_case3.DeepCopy()); + expected_list_merged.Set(kTestPolicyName4, expected_case4.DeepCopy()); + expected_list_merged.Set(kTestPolicyName5, expected_case5.DeepCopy()); + expected_list_merged.Set(kTestPolicyName6, expected_case6.DeepCopy()); + expected_list_merged.Set(kTestPolicyName7, expected_case7.DeepCopy()); + expected_list_merged.Set(kTestPolicyName8, expected_case8.DeepCopy()); + + PolicyMap list_merged = policy_not_merged.Clone(); + + PolicyMap list_merged_wildcard = policy_not_merged.Clone(); + + // Merging with no restrictions specified + PolicyListMerger empty_policy_list({}); + list_merged.MergeValues({&empty_policy_list}); + EXPECT_TRUE(list_merged.Equals(policy_not_merged)); + + PolicyListMerger bad_policy_list({"unknown"}); + // Merging with wrong restrictions specified + list_merged.MergeValues({&bad_policy_list}); + EXPECT_TRUE(list_merged.Equals(policy_not_merged)); + + // Merging lists restrictions specified + PolicyListMerger good_policy_list( + {kTestPolicyName1, kTestPolicyName2, kTestPolicyName3, kTestPolicyName4, + kTestPolicyName5, kTestPolicyName6, kTestPolicyName7, kTestPolicyName8}); + PolicyListMerger wildcard_policy_list({"*"}); + list_merged.MergeValues({&good_policy_list}); + EXPECT_TRUE(list_merged.Equals(expected_list_merged)); + + PolicyMap expected_list_merged_wildcard = expected_list_merged.Clone(); + expected_list_merged_wildcard.Set(kTestPolicyName5, case5.DeepCopy()); + list_merged_wildcard.MergeValues({&wildcard_policy_list}); + EXPECT_TRUE(list_merged_wildcard.Equals(expected_list_merged_wildcard)); +} + +TEST_F(PolicyMapTest, MergeValuesDictionary) { + base::Value dict_a(base::Value::Type::DICTIONARY); + dict_a.SetBoolKey("keyA", true); + + base::Value dict_b(base::Value::Type::DICTIONARY); + dict_b.SetStringKey("keyB", "ValueB2"); + dict_b.SetStringKey("keyC", "ValueC2"); + dict_b.SetStringKey("keyD", "ValueD2"); + + base::Value dict_c(base::Value::Type::DICTIONARY); + dict_c.SetStringKey("keyA", "ValueA"); + dict_c.SetStringKey("keyB", "ValueB"); + dict_c.SetStringKey("keyC", "ValueC"); + dict_c.SetStringKey("keyD", "ValueD"); + dict_c.SetStringKey("keyZ", "ValueZ"); + + base::Value dict_d(base::Value::Type::DICTIONARY); + dict_d.SetStringKey("keyC", "ValueC3"); + + base::Value dict_e(base::Value::Type::DICTIONARY); + dict_e.SetStringKey("keyD", "ValueD4"); + dict_e.SetIntKey("keyE", 123); + + base::Value dict_f(base::Value::Type::DICTIONARY); + dict_f.SetStringKey("keyX", "ValueX"); + dict_f.SetStringKey("keyE", "ValueE5"); + + // Case 1: kTestPolicyName1 - Merging should only keep keys with the highest + // priority + PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, dict_a.Clone(), nullptr); + case1.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, dict_b.Clone(), nullptr)); + case1.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_COMMAND_LINE, dict_c.Clone(), nullptr)); + + base::Value merged_dict_case1(base::Value::Type::DICTIONARY); + merged_dict_case1.MergeDictionary(&dict_c); + merged_dict_case1.MergeDictionary(&dict_b); + merged_dict_case1.MergeDictionary(&dict_a); + + PolicyMap::Entry expected_case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, + merged_dict_case1.Clone(), nullptr); + expected_case1.AddConflictingPolicy(case1.DeepCopy()); + + // Case 2 - kTestPolicyName2 + // Policies should only be merged with other policies with the same target, + // level and scope. + PolicyMap::Entry case2(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, dict_e.Clone(), nullptr); + + case2.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, dict_f.Clone(), nullptr)); + + case2.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, dict_a.Clone(), nullptr)); + + base::Value merged_dict_case2(base::Value::Type::DICTIONARY); + merged_dict_case2.MergeDictionary(&dict_f); + merged_dict_case2.MergeDictionary(&dict_e); + + PolicyMap::Entry expected_case2(POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, + merged_dict_case2.Clone(), nullptr); + expected_case2.AddConflictingPolicy(case2.DeepCopy()); + + // Case 3 - kTestPolicyName3 + // Enterprise default policies should not be merged with other sources. + PolicyMap::Entry case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, dict_a.Clone(), nullptr); + + case3.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_COMMAND_LINE, dict_b.Clone(), nullptr)); + + case3.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, dict_e.Clone(), nullptr)); + + case3.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, dict_f.Clone(), nullptr)); + + base::Value merged_dict_case3(base::Value::Type::DICTIONARY); + merged_dict_case3.MergeDictionary(&dict_b); + merged_dict_case3.MergeDictionary(&dict_a); + + PolicyMap::Entry expected_case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, + merged_dict_case3.Clone(), nullptr); + expected_case3.AddConflictingPolicy(case3.DeepCopy()); + + // Case 4 - kTestPolicyName4 + // Policies with a single source should be merged. + PolicyMap::Entry case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, dict_a.Clone(), nullptr); + PolicyMap::Entry expected_case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, dict_a.Clone(), + nullptr); + expected_case4.AddConflictingPolicy(case4.DeepCopy()); + + // Case 5 - kTestPolicyName5 + // Policies that are not dictionaries should not be merged. + // If such a policy is explicitly in the list of policies to merge, an error + // is added to the entry and the policy stays intact. + PolicyMap::Entry case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, base::Value("bad stuff"), + nullptr); + + PolicyMap::Entry expected_case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, + base::Value("bad stuff"), nullptr); + expected_case5.AddMessage( + PolicyMap::MessageType::kError, + IDS_POLICY_DICTIONARY_MERGING_WRONG_POLICY_TYPE_SPECIFIED); + + // Case 6 - kTestPolicyName6 + // User cloud policies should not be merged with other sources. + PolicyMap::Entry case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, dict_a.Clone(), nullptr); + case6.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, dict_e.Clone(), nullptr)); + case6.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, dict_f.Clone(), nullptr)); + PolicyMap::Entry expected_case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, dict_a.Clone(), + nullptr); + expected_case6.AddConflictingPolicy(case6.DeepCopy()); + + // Case 7 - kTestPolicyName7 + // User platform policies should not be merged under any circumstances. + PolicyMap::Entry case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, dict_a.Clone(), nullptr); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, dict_b.Clone(), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, dict_c.Clone(), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, dict_d.Clone(), nullptr)); + case7.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_COMMAND_LINE, dict_e.Clone(), nullptr)); + PolicyMap::Entry expected_case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, dict_a.Clone(), + nullptr); + expected_case7.AddConflictingPolicy(case7.DeepCopy()); + + // Case 8 - kTestPolicyName8 + // Policies that are not dictionaries should not be merged. + // If such a policy is explicitly in the list of policies to merge, an error + // is added to the entry and the policy stays intact. + PolicyMap::Entry case8(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, dict_a.Clone(), nullptr); + + PolicyMap::Entry expected_case8 = case8.DeepCopy(); + + expected_case8.AddMessage(PolicyMap::MessageType::kError, + IDS_POLICY_DICTIONARY_MERGING_POLICY_NOT_ALLOWED); + + PolicyMap policy_not_merged; + policy_not_merged.Set(kTestPolicyName1, case1.DeepCopy()); + policy_not_merged.Set(kTestPolicyName2, case2.DeepCopy()); + policy_not_merged.Set(kTestPolicyName3, case3.DeepCopy()); + policy_not_merged.Set(kTestPolicyName4, case4.DeepCopy()); + policy_not_merged.Set(kTestPolicyName5, case5.DeepCopy()); + policy_not_merged.Set(kTestPolicyName6, case6.DeepCopy()); + policy_not_merged.Set(kTestPolicyName7, case7.DeepCopy()); + policy_not_merged.Set(kTestPolicyName8, case8.DeepCopy()); + + PolicyMap expected_list_merged; + expected_list_merged.Set(kTestPolicyName1, expected_case1.DeepCopy()); + expected_list_merged.Set(kTestPolicyName2, expected_case2.DeepCopy()); + expected_list_merged.Set(kTestPolicyName3, expected_case3.DeepCopy()); + expected_list_merged.Set(kTestPolicyName4, expected_case4.DeepCopy()); + expected_list_merged.Set(kTestPolicyName5, expected_case5.DeepCopy()); + expected_list_merged.Set(kTestPolicyName6, expected_case6.DeepCopy()); + expected_list_merged.Set(kTestPolicyName7, expected_case7.DeepCopy()); + expected_list_merged.Set(kTestPolicyName8, expected_case8.DeepCopy()); + + PolicyMap list_merged = policy_not_merged.Clone(); + + PolicyMap list_merged_wildcard = policy_not_merged.Clone(); + + // Merging with no restrictions specified + PolicyDictionaryMerger empty_policy_list({}); + list_merged.MergeValues({&empty_policy_list}); + EXPECT_TRUE(list_merged.Equals(policy_not_merged)); + + PolicyDictionaryMerger bad_policy_list({"unknown"}); + // Merging with wrong restrictions specified + list_merged.MergeValues({&bad_policy_list}); + EXPECT_TRUE(list_merged.Equals(policy_not_merged)); + + // Merging lists restrictions specified + PolicyDictionaryMerger good_policy_list( + {kTestPolicyName1, kTestPolicyName2, kTestPolicyName3, kTestPolicyName4, + kTestPolicyName5, kTestPolicyName6, kTestPolicyName7, kTestPolicyName8}); + good_policy_list.SetAllowedPoliciesForTesting( + {kTestPolicyName1, kTestPolicyName2, kTestPolicyName3, kTestPolicyName4, + kTestPolicyName5, kTestPolicyName6, kTestPolicyName7}); + PolicyDictionaryMerger wildcard_policy_list({"*"}); + wildcard_policy_list.SetAllowedPoliciesForTesting( + {kTestPolicyName1, kTestPolicyName2, kTestPolicyName3, kTestPolicyName4, + kTestPolicyName5, kTestPolicyName6, kTestPolicyName7}); + list_merged.MergeValues({&good_policy_list}); + EXPECT_TRUE(list_merged.Equals(expected_list_merged)); + + PolicyMap expected_list_merged_wildcard = expected_list_merged.Clone(); + expected_list_merged_wildcard.Set(kTestPolicyName5, case5.DeepCopy()); + expected_list_merged_wildcard.Set(kTestPolicyName8, case8.DeepCopy()); + list_merged_wildcard.MergeValues({&wildcard_policy_list}); + EXPECT_TRUE(list_merged_wildcard.Equals(expected_list_merged_wildcard)); +} + +TEST_F(PolicyMapTest, MergeValuesGroup) { + std::vector<base::Value> abc = GetListStorage<std::string>({"a", "b", "c"}); + std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"}); + std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"}); + std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"}); + + // Case 1 - kTestPolicyName1 + // Should not be affected by the atomic groups + PolicyMap::Entry platform_user_mandatory( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, + base::Value(abc), nullptr); + + platform_user_mandatory.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(cd), nullptr)); + + platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr)); + + platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry( + POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr)); + + // Case 2 - policy::key::kExtensionInstallBlocklist + // This policy is part of the atomic group "Extensions" and has the highest + // source in its group, its value should remain the same. + PolicyMap::Entry platform_machine_mandatory( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(ab), nullptr); + + platform_machine_mandatory.AddConflictingPolicy( + PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(cd), nullptr)); + + // Case 3 - policy::key::kExtensionInstallAllowlist + // This policy is part of the atomic group "Extensions" and has a lower + // source than policy::key::kExtensionInstallBlocklist from the same group, + // its value should be ignored. + PolicyMap::Entry cloud_machine_mandatory( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value(ef), nullptr); + auto cloud_machine_mandatory_ignored = cloud_machine_mandatory.DeepCopy(); + cloud_machine_mandatory_ignored.SetIgnoredByPolicyAtomicGroup(); + + // Case 4 - policy::key::kExtensionInstallBlocklist + // This policy is part of the atomic group "Extensions" and has the highest + // source in its group, its value should remain the same. + PolicyMap::Entry platform_machine_recommended( + POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(ab), nullptr); + + PolicyMap policy_not_merged; + policy_not_merged.Set(kTestPolicyName1, platform_user_mandatory.DeepCopy()); + policy_not_merged.Set(policy::key::kExtensionInstallBlocklist, + platform_machine_mandatory.DeepCopy()); + policy_not_merged.Set(policy::key::kExtensionInstallAllowlist, + cloud_machine_mandatory.DeepCopy()); + policy_not_merged.Set(policy::key::kExtensionInstallForcelist, + platform_machine_recommended.DeepCopy()); + + PolicyMap group_merged = policy_not_merged.Clone(); + PolicyGroupMerger group_merger; + group_merged.MergeValues({&group_merger}); + + PolicyMap expected_group_merged; + expected_group_merged.Set(kTestPolicyName1, + platform_user_mandatory.DeepCopy()); + expected_group_merged.Set(policy::key::kExtensionInstallBlocklist, + platform_machine_mandatory.DeepCopy()); + expected_group_merged.Set(policy::key::kExtensionInstallAllowlist, + cloud_machine_mandatory_ignored.DeepCopy()); + expected_group_merged.Set(policy::key::kExtensionInstallForcelist, + platform_machine_recommended.DeepCopy()); + + EXPECT_TRUE(group_merged.Equals(expected_group_merged)); +} + +TEST_F(PolicyMapTest, LoadFromSetsLevelScopeAndSource) { + base::DictionaryValue policies; + policies.SetStringKey("TestPolicy1", "google.com"); + policies.SetBoolKey("TestPolicy2", true); + policies.SetIntKey("TestPolicy3", -12321); + + PolicyMap loaded; + loaded.LoadFrom(&policies, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM); + + PolicyMap expected; + expected.Set("TestPolicy1", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value("google.com"), nullptr); + expected.Set("TestPolicy2", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(true), nullptr); + expected.Set("TestPolicy3", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(-12321), nullptr); + EXPECT_TRUE(loaded.Equals(expected)); +} + +bool IsMandatory(const PolicyMap::PolicyMapType::const_iterator iter) { + return iter->second.level == POLICY_LEVEL_MANDATORY; +} + +TEST_F(PolicyMapTest, EraseNonmatching) { + PolicyMap a; + a.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("google.com"), nullptr); + a.Set(kTestPolicyName2, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + + a.EraseNonmatching(base::BindRepeating(&IsMandatory)); + + PolicyMap b; + b.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("google.com"), nullptr); + EXPECT_TRUE(a.Equals(b)); +} + +TEST_F(PolicyMapTest, EntryAddConflict) { + std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"}); + std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"}); + std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"}); + std::vector<base::Value> gh = GetListStorage<std::string>({"g", "h"}); + + // Case 1: Non-nested conflicts + PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr); + PolicyMap::Entry conflict11(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr); + PolicyMap::Entry conflict12(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr); + PolicyMap::Entry conflict13(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(gh), nullptr); + PolicyMap::Entry conflict14(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr); + + case1.AddConflictingPolicy(conflict11.DeepCopy()); + case1.AddConflictingPolicy(conflict12.DeepCopy()); + case1.AddConflictingPolicy(conflict13.DeepCopy()); + case1.AddConflictingPolicy(conflict14.DeepCopy()); + + EXPECT_TRUE(case1.conflicts.size() == 4); + EXPECT_TRUE(case1.conflicts.at(0).entry().Equals(conflict11)); + EXPECT_TRUE(case1.conflicts.at(1).entry().Equals(conflict12)); + EXPECT_TRUE(case1.conflicts.at(2).entry().Equals(conflict13)); + EXPECT_TRUE(case1.conflicts.at(3).entry().Equals(conflict14)); + EXPECT_EQ(case1.conflicts.at(0).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(case1.conflicts.at(1).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(case1.conflicts.at(2).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(case1.conflicts.at(3).conflict_type(), + PolicyMap::ConflictType::Supersede); + + // Case 2: Nested conflicts + PolicyMap::Entry case2(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr); + PolicyMap::Entry conflict21(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr); + PolicyMap::Entry conflict22(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr); + PolicyMap::Entry conflict23(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr); + PolicyMap::Entry conflict24(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(gh), nullptr); + + conflict21.AddConflictingPolicy(conflict22.DeepCopy()); + conflict21.AddConflictingPolicy(conflict23.DeepCopy()); + conflict21.AddConflictingPolicy(conflict24.DeepCopy()); + case2.AddConflictingPolicy(conflict21.DeepCopy()); + + EXPECT_TRUE(case2.conflicts.size() == 4); + EXPECT_TRUE(case2.conflicts.at(0).entry().Equals(conflict22)); + EXPECT_TRUE(case2.conflicts.at(1).entry().Equals(conflict23)); + EXPECT_TRUE(case2.conflicts.at(2).entry().Equals(conflict24)); + EXPECT_TRUE(conflict21.conflicts.at(0).entry().Equals(conflict22)); + EXPECT_TRUE(conflict21.conflicts.at(1).entry().Equals(conflict23)); + EXPECT_TRUE(conflict21.conflicts.at(2).entry().Equals(conflict24)); + EXPECT_EQ(case2.conflicts.at(0).conflict_type(), + PolicyMap::ConflictType::Supersede); + EXPECT_EQ(case2.conflicts.at(1).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(case2.conflicts.at(2).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(case2.conflicts.at(3).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(conflict21.conflicts.at(0).conflict_type(), + PolicyMap::ConflictType::Supersede); + EXPECT_EQ(conflict21.conflicts.at(1).conflict_type(), + PolicyMap::ConflictType::Override); + EXPECT_EQ(conflict21.conflicts.at(2).conflict_type(), + PolicyMap::ConflictType::Override); +} + +TEST_F(PolicyMapTest, BlockedEntry) { + PolicyMap::Entry entry_a(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("a"), nullptr); + PolicyMap::Entry entry_b = entry_a.DeepCopy(); + entry_b.set_value(base::Value("b")); + PolicyMap::Entry entry_c_blocked = entry_a.DeepCopy(); + entry_c_blocked.set_value(base::Value("c")); + entry_c_blocked.SetBlocked(); + + PolicyMap policies; + policies.Set("a", entry_a.DeepCopy()); + policies.Set("b", entry_b.DeepCopy()); + policies.Set("c", entry_c_blocked.DeepCopy()); + + const size_t expected_size = 3; + EXPECT_EQ(policies.size(), expected_size); + + EXPECT_TRUE(policies.Get("a")->Equals(entry_a)); + EXPECT_TRUE(policies.Get("b")->Equals(entry_b)); + EXPECT_EQ(policies.Get("c"), nullptr); + + EXPECT_TRUE(policies.GetMutable("a")->Equals(entry_a)); + EXPECT_TRUE(policies.GetMutable("b")->Equals(entry_b)); + EXPECT_EQ(policies.GetMutable("c"), nullptr); + + EXPECT_EQ(*policies.GetValue("a", base::Value::Type::STRING), + *entry_a.value(base::Value::Type::STRING)); + EXPECT_EQ(*policies.GetValue("b", base::Value::Type::STRING), + *entry_b.value(base::Value::Type::STRING)); + EXPECT_EQ(policies.GetValue("c", base::Value::Type::STRING), nullptr); + + EXPECT_EQ(*policies.GetValueUnsafe("a"), *entry_a.value_unsafe()); + EXPECT_EQ(*policies.GetValueUnsafe("b"), *entry_b.value_unsafe()); + EXPECT_EQ(policies.GetValueUnsafe("c"), nullptr); + + EXPECT_EQ(*policies.GetMutableValue("a", base::Value::Type::STRING), + *entry_a.value(base::Value::Type::STRING)); + EXPECT_EQ(*policies.GetMutableValue("b", base::Value::Type::STRING), + *entry_b.value(base::Value::Type::STRING)); + EXPECT_EQ(policies.GetMutableValue("c", base::Value::Type::STRING), nullptr); + + EXPECT_EQ(*policies.GetMutableValueUnsafe("a"), *entry_a.value_unsafe()); + EXPECT_EQ(*policies.GetMutableValueUnsafe("b"), *entry_b.value_unsafe()); + EXPECT_EQ(policies.GetMutableValueUnsafe("c"), nullptr); + + EXPECT_TRUE(policies.GetUntrusted("a")->Equals(entry_a)); + EXPECT_TRUE(policies.GetUntrusted("b")->Equals(entry_b)); + EXPECT_TRUE(policies.GetUntrusted("c")->Equals(entry_c_blocked)); + + EXPECT_TRUE(policies.GetMutableUntrusted("a")->Equals(entry_a)); + EXPECT_TRUE(policies.GetMutableUntrusted("b")->Equals(entry_b)); + EXPECT_TRUE(policies.GetMutableUntrusted("c")->Equals(entry_c_blocked)); + + EXPECT_FALSE(policies.GetUntrusted("a")->ignored()); + EXPECT_FALSE(policies.GetUntrusted("b")->ignored()); + EXPECT_TRUE(policies.GetUntrusted("c")->ignored()); + + size_t iterated_values = 0; + for (auto it = policies.begin(); it != policies.end(); + ++it, ++iterated_values) { + } + EXPECT_TRUE(iterated_values == expected_size); +} + +TEST_F(PolicyMapTest, InvalidEntry) { + PolicyMap::Entry entry_a(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("a"), nullptr); + PolicyMap::Entry entry_b_invalid = entry_a.DeepCopy(); + entry_b_invalid.set_value(base::Value("b")); + entry_b_invalid.SetInvalid(); + + PolicyMap policies; + policies.Set("a", entry_a.DeepCopy()); + policies.Set("b", entry_b_invalid.DeepCopy()); + + const size_t expected_size = 2; + EXPECT_EQ(policies.size(), expected_size); + + EXPECT_TRUE(policies.Get("a")->Equals(entry_a)); + EXPECT_EQ(policies.Get("b"), nullptr); + + EXPECT_TRUE(policies.GetMutable("a")->Equals(entry_a)); + EXPECT_EQ(policies.GetMutable("b"), nullptr); + + EXPECT_EQ(*policies.GetValue("a", base::Value::Type::STRING), + *entry_a.value(base::Value::Type::STRING)); + EXPECT_EQ(policies.GetValue("b", base::Value::Type::STRING), nullptr); + + EXPECT_EQ(*policies.GetValueUnsafe("a"), *entry_a.value_unsafe()); + EXPECT_EQ(policies.GetValueUnsafe("b"), nullptr); + + EXPECT_EQ(*policies.GetMutableValue("a", base::Value::Type::STRING), + *entry_a.value(base::Value::Type::STRING)); + EXPECT_EQ(policies.GetMutableValue("b", base::Value::Type::STRING), nullptr); + + EXPECT_EQ(*policies.GetMutableValueUnsafe("a"), *entry_a.value_unsafe()); + EXPECT_EQ(policies.GetMutableValueUnsafe("b"), nullptr); + + EXPECT_TRUE(policies.GetUntrusted("a")->Equals(entry_a)); + EXPECT_TRUE(policies.GetUntrusted("b")->Equals(entry_b_invalid)); + + EXPECT_TRUE(policies.GetMutableUntrusted("a")->Equals(entry_a)); + EXPECT_TRUE(policies.GetMutableUntrusted("b")->Equals(entry_b_invalid)); + + EXPECT_FALSE(policies.GetUntrusted("a")->ignored()); + EXPECT_TRUE(policies.GetUntrusted("b")->ignored()); + + size_t iterated_values = 0; + for (auto it = policies.begin(); it != policies.end(); + ++it, ++iterated_values) { + } + EXPECT_EQ(iterated_values, expected_size); + + policies.SetAllInvalid(); + EXPECT_TRUE(policies.GetUntrusted("a")->ignored()); + EXPECT_TRUE(policies.GetUntrusted("b")->ignored()); +} + +TEST_F(PolicyMapTest, Affiliation) { + PolicyMap policies; + EXPECT_FALSE(policies.IsUserAffiliated()); + + base::flat_set<std::string> user_ids; + user_ids.insert("a"); + base::flat_set<std::string> device_ids; + device_ids.insert("b"); + policies.SetUserAffiliationIds(user_ids); + policies.SetDeviceAffiliationIds(device_ids); + + // Affiliation check fails because user and device IDs don't have at least one + // ID in common. + EXPECT_FALSE(policies.IsUserAffiliated()); + + user_ids.insert("b"); + device_ids.insert("c"); + policies.SetUserAffiliationIds(user_ids); + policies.SetDeviceAffiliationIds(device_ids); + + // Affiliation check succeeds now that 'a' is present in user and device IDs. + EXPECT_TRUE(policies.IsUserAffiliated()); +} + +class PolicyMapMergeTest + : public PolicyMapTestBase, + public testing::TestWithParam< + std::tuple</*cloud_policy_overrides_platform_policy=*/bool, + /*cloud_user_policy_overrides_cloud_machine_policy=*/bool, + /*is_user_affiliated=*/bool, + /*metapolicies_are_incoming=*/bool>> { + public: + bool CloudPolicyOverridesPlatformPolicy() const { + return std::get<0>(GetParam()); + } + + bool CloudUserPolicyOverridesCloudMachinePolicy() const { + return std::get<1>(GetParam()); + } + + bool IsUserAffiliated() const { return std::get<2>(GetParam()); } + + bool MetapoliciesAreIncoming() const { return std::get<3>(GetParam()); } + + void PopulateExpectedPolicyMap(PolicyMap& policy_map_expected, + const PolicyMap& policy_map_1, + const PolicyMap& policy_map_2) { + // Setting the metapolicies. + policy_map_expected.Set( + key::kCloudPolicyOverridesPlatformPolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map_expected.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + + // Expected behavior independent of metapolicy values and affiliation. + // ------------------------------------------------------------------- + // |policy_map_1| has precedence over |policy_map_2|. + policy_map_expected.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value(true), nullptr); + policy_map_expected.GetMutable(kTestPolicyName2) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName2) + ->AddConflictingPolicy(policy_map_2.Get(kTestPolicyName2)->DeepCopy()); + policy_map_expected.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, absl::nullopt, + CreateExternalDataFetcher("a")); + policy_map_expected.GetMutable(kTestPolicyName3) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName3) + ->AddConflictingPolicy(policy_map_2.Get(kTestPolicyName3)->DeepCopy()); + // Cloud machine over platform user for recommended policies. + policy_map_expected.Set(kTestPolicyName4, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value(true), nullptr); + policy_map_expected.GetMutable(kTestPolicyName4) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName4) + ->AddConflictingPolicy(policy_map_1.Get(kTestPolicyName4)->DeepCopy()); + // Mandatory over recommended level. + policy_map_expected.Set(kTestPolicyName5, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(std::string()), nullptr); + policy_map_expected.GetMutable(kTestPolicyName5) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName5) + ->AddConflictingPolicy(policy_map_1.Get(kTestPolicyName5)->DeepCopy()); + // Merge new policy. + policy_map_expected.Set(kTestPolicyName6, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value(true), nullptr); + // Platform over default source. + policy_map_expected.Set(kTestPolicyName7, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, + base::Value(true), nullptr); + policy_map_expected.GetMutable(kTestPolicyName7)->SetBlocked(); + + // Expected behavior that depends on metapolicy values and affiliation. + // -------------------------------------------------------------------- +#if !BUILDFLAG(IS_CHROMEOS) + if (CloudPolicyOverridesPlatformPolicy() && + CloudUserPolicyOverridesCloudMachinePolicy() && IsUserAffiliated()) { + // Cloud user over cloud machine source. + policy_map_expected.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("google.com"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddConflictingPolicy( + policy_map_2.Get(kTestPolicyName1)->DeepCopy()); + // Cloud machine over platform machine when platform is blocked. + policy_map_expected.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("non-blocked cloud policy"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddConflictingPolicy( + policy_map_1.Get(kTestPolicyName8)->DeepCopy()); + // policy_map_expected.GetMutable(kTestPolicyName8)->SetBlocked(); + } else if (CloudUserPolicyOverridesCloudMachinePolicy() && + IsUserAffiliated()) { + // Cloud user over cloud machine source. + policy_map_expected.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("google.com"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddConflictingPolicy( + policy_map_2.Get(kTestPolicyName1)->DeepCopy()); + // Platform machine over cloud machine even when platform is blocked. + policy_map_expected.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value("blocked platform policy"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddConflictingPolicy( + policy_map_2.Get(kTestPolicyName8)->DeepCopy()); + policy_map_expected.GetMutable(kTestPolicyName8)->SetBlocked(); + } else if (CloudPolicyOverridesPlatformPolicy()) { + // Machine over user scope. + policy_map_expected.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("chromium.org"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddConflictingPolicy( + policy_map_1.Get(kTestPolicyName1)->DeepCopy()); + // Cloud machine over platform machine when platform is blocked. + policy_map_expected.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("non-blocked cloud policy"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddConflictingPolicy( + policy_map_1.Get(kTestPolicyName8)->DeepCopy()); + // policy_map_expected.GetMutable(kTestPolicyName8)->SetBlocked(); + } else { +#endif // !BUILDFLAG(IS_CHROMEOS) + // Machine over user scope. + policy_map_expected.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("chromium.org"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName1) + ->AddConflictingPolicy( + policy_map_1.Get(kTestPolicyName1)->DeepCopy()); + // Platform machine over cloud machine even when platform is blocked. + policy_map_expected.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value("blocked platform policy"), nullptr); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(kTestPolicyName8) + ->AddConflictingPolicy( + policy_map_2.Get(kTestPolicyName8)->DeepCopy()); + policy_map_expected.GetMutable(kTestPolicyName8)->SetBlocked(); +#if !BUILDFLAG(IS_CHROMEOS) + } +#endif // !BUILDFLAG(IS_CHROMEOS) + } + + void PopulateExpectedMetapolicyMap( + PolicyMap& policy_map_expected, + const PolicyMap& policy_map_1, + const PolicyMap& policy_map_2, + std::unique_ptr<base::ListValue> merge_list_1, + std::unique_ptr<base::ListValue> merge_list_2) { + // Platform machine overrides cloud machine because modified priorities + // don't apply to precedence metapolicies. + policy_map_expected.Set( + key::kCloudPolicyOverridesPlatformPolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map_expected.GetMutable(key::kCloudPolicyOverridesPlatformPolicy) + ->AddMessage(CloudPolicyOverridesPlatformPolicy() + ? PolicyMap::MessageType::kWarning + : PolicyMap::MessageType::kInfo, + CloudPolicyOverridesPlatformPolicy() + ? IDS_POLICY_CONFLICT_DIFF_VALUE + : IDS_POLICY_CONFLICT_SAME_VALUE); + policy_map_expected.GetMutable(key::kCloudPolicyOverridesPlatformPolicy) + ->AddConflictingPolicy( + policy_map_2.Get(key::kCloudPolicyOverridesPlatformPolicy) + ->DeepCopy()); + policy_map_expected.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + policy_map_expected + .GetMutable(key::kCloudUserPolicyOverridesCloudMachinePolicy) + ->AddMessage(CloudUserPolicyOverridesCloudMachinePolicy() + ? PolicyMap::MessageType::kWarning + : PolicyMap::MessageType::kInfo, + CloudUserPolicyOverridesCloudMachinePolicy() + ? IDS_POLICY_CONFLICT_DIFF_VALUE + : IDS_POLICY_CONFLICT_SAME_VALUE); + policy_map_expected + .GetMutable(key::kCloudUserPolicyOverridesCloudMachinePolicy) + ->AddConflictingPolicy( + policy_map_1.Get(key::kCloudUserPolicyOverridesCloudMachinePolicy) + ->DeepCopy()); +#if !BUILDFLAG(IS_CHROMEOS) + if (CloudPolicyOverridesPlatformPolicy()) { + // Cloud machine overrides platform machine because modified priorities + // apply to merging metapolicies. + policy_map_expected.Set(key::kPolicyListMultipleSourceMergeList, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, merge_list_2->Clone(), + nullptr); + policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList) + ->AddConflictingPolicy( + policy_map_1.Get(key::kPolicyListMultipleSourceMergeList) + ->DeepCopy()); + } else { +#endif // !BUILDFLAG(IS_CHROMEOS) + // Platform machine overrides cloud machine with default precedence. + policy_map_expected.Set(key::kPolicyListMultipleSourceMergeList, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, merge_list_1->Clone(), + nullptr); + policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList) + ->AddMessage(PolicyMap::MessageType::kWarning, + IDS_POLICY_CONFLICT_DIFF_VALUE); + policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList) + ->AddConflictingPolicy( + policy_map_2.Get(key::kPolicyListMultipleSourceMergeList) + ->DeepCopy()); +#if !BUILDFLAG(IS_CHROMEOS) + } +#endif // !BUILDFLAG(IS_CHROMEOS) + } +}; + +TEST_P(PolicyMapMergeTest, MergeFrom) { + PolicyMap policy_map_1; + if (IsUserAffiliated()) { + base::flat_set<std::string> affiliation_ids; + affiliation_ids.insert("12345"); + // Treat user as affiliated by setting identical user and device IDs. + policy_map_1.SetUserAffiliationIds(affiliation_ids); + policy_map_1.SetDeviceAffiliationIds(affiliation_ids); + } + if (!MetapoliciesAreIncoming()) { + // Metapolicies are set in the base PolicyMap. + policy_map_1.Set( + key::kCloudPolicyOverridesPlatformPolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map_1.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + } + policy_map_1.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("google.com"), nullptr); + policy_map_1.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, base::Value(true), + nullptr); + policy_map_1.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, + absl::nullopt, CreateExternalDataFetcher("a")); + policy_map_1.Set(kTestPolicyName4, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, + base::Value(false), nullptr); + policy_map_1.Set(kTestPolicyName5, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("google.com/q={x}"), nullptr); + policy_map_1.Set(kTestPolicyName7, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), + nullptr); + policy_map_1.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value("blocked platform policy"), nullptr); + + PolicyMap policy_map_2; + if (MetapoliciesAreIncoming()) { + // Metapolicies are set in the incoming PolicyMap. + policy_map_2.Set( + key::kCloudPolicyOverridesPlatformPolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map_2.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + } + policy_map_2.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("chromium.org"), nullptr); + policy_map_2.Set(kTestPolicyName2, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value(false), nullptr); + policy_map_2.Set(kTestPolicyName3, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, + absl::nullopt, CreateExternalDataFetcher("b")); + policy_map_2.Set(kTestPolicyName4, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, base::Value(true), + nullptr); + policy_map_2.Set(kTestPolicyName5, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(std::string()), nullptr); + policy_map_2.Set(kTestPolicyName6, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(true), + nullptr); + policy_map_2.Set(kTestPolicyName7, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(true), nullptr); + policy_map_2.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + base::Value("non-blocked cloud policy"), nullptr); + + PolicyMap policy_map_expected; + PopulateExpectedPolicyMap(policy_map_expected, policy_map_1, policy_map_2); + + policy_map_1.GetMutable(kTestPolicyName7)->SetBlocked(); + policy_map_2.GetMutable(kTestPolicyName7)->SetBlocked(); + policy_map_1.GetMutable(kTestPolicyName8)->SetBlocked(); + policy_map_1.MergeFrom(policy_map_2); + + EXPECT_TRUE(policy_map_1.Equals(policy_map_expected)); +} + +TEST_P(PolicyMapMergeTest, MergeFrom_Metapolicies) { + // Define the lists of policies that will be used by the merging metapolicies. + std::unique_ptr<base::ListValue> merge_list_1 = + std::make_unique<base::ListValue>(); + merge_list_1->Append(base::Value(kTestPolicyName1)); + std::unique_ptr<base::ListValue> merge_list_2 = + std::make_unique<base::ListValue>(); + merge_list_2->Append(base::Value(kTestPolicyName2)); + + PolicyMap policy_map_1; + if (IsUserAffiliated()) { + base::flat_set<std::string> affiliation_ids; + affiliation_ids.insert("12345"); + policy_map_1.SetUserAffiliationIds(affiliation_ids); + policy_map_1.SetDeviceAffiliationIds(affiliation_ids); + } + policy_map_1.Set(key::kCloudPolicyOverridesPlatformPolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map_1.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + policy_map_1.Set(key::kPolicyListMultipleSourceMergeList, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, merge_list_1->Clone(), nullptr); + + PolicyMap policy_map_2; + policy_map_2.Set(key::kCloudPolicyOverridesPlatformPolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + policy_map_2.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + policy_map_2.Set(key::kPolicyListMultipleSourceMergeList, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, merge_list_2->Clone(), nullptr); + + PolicyMap policy_map_expected; + PopulateExpectedMetapolicyMap(policy_map_expected, policy_map_1, policy_map_2, + std::move(merge_list_1), + std::move(merge_list_2)); + + policy_map_1.MergeFrom(policy_map_2); + + EXPECT_TRUE(policy_map_1.Equals(policy_map_expected)); +} + +INSTANTIATE_TEST_SUITE_P(PolicyMapMergeTestInstance, + PolicyMapMergeTest, + testing::Combine(testing::Values(false, true), + testing::Values(false, true), + testing::Values(false, true), + testing::Values(false, true))); + +#if !BUILDFLAG(IS_CHROMEOS) +class PolicyMapPriorityTest + : public testing::TestWithParam< + std::tuple</*cloud_policy_overrides_platform_policy=*/bool, + /*cloud_user_policy_overrides_cloud_machine_policy=*/bool, + /*is_user_affiliated=*/bool>> { + public: + bool CloudPolicyOverridesPlatformPolicy() { return std::get<0>(GetParam()); } + + bool CloudUserPolicyOverridesCloudMachinePolicy() { + return std::get<1>(GetParam()); + } + + bool IsUserAffiliated() { return std::get<2>(GetParam()); } + + void CheckPriorityConditions(PolicyMap& policy_map) { + PolicyMap::Entry platform_machine( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(), nullptr); + PolicyMap::Entry platform_user(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, base::Value(), + nullptr); + PolicyMap::Entry cloud_machine(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, base::Value(), nullptr); + PolicyMap::Entry cloud_user(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(), nullptr); + PolicyMap::Entry command_line(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_COMMAND_LINE, base::Value(), + nullptr); + PolicyMap::Entry enterprise_default( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(), nullptr); + + // The policy priority conditions depend on the precedence metapolicy values + // and user affiliation. + if (CloudPolicyOverridesPlatformPolicy() && + CloudUserPolicyOverridesCloudMachinePolicy() && IsUserAffiliated()) { + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, platform_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_machine)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_machine, platform_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(cloud_machine, cloud_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(platform_user, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_user, command_line)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_user, enterprise_default)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(command_line, enterprise_default)); + } else if (CloudUserPolicyOverridesCloudMachinePolicy() && + IsUserAffiliated()) { + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, platform_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_machine)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_machine, platform_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(cloud_machine, cloud_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(platform_user, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_user, command_line)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_user, enterprise_default)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(command_line, enterprise_default)); + } else if (CloudPolicyOverridesPlatformPolicy()) { + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, platform_user)); + EXPECT_FALSE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_machine)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_machine, platform_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_machine, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(platform_user, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_user, command_line)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_user, enterprise_default)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(command_line, enterprise_default)); + } else { + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, platform_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_machine)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(platform_machine, cloud_user)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_machine, platform_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_machine, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(platform_user, cloud_user)); + EXPECT_TRUE(policy_map.EntryHasHigherPriority(cloud_user, command_line)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(cloud_user, enterprise_default)); + EXPECT_TRUE( + policy_map.EntryHasHigherPriority(command_line, enterprise_default)); + } + } +}; + +TEST_P(PolicyMapPriorityTest, PriorityCheck) { + PolicyMap policy_map; + + // Update the metapolicy values. + policy_map.Set(key::kCloudPolicyOverridesPlatformPolicy, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PLATFORM, + base::Value(CloudPolicyOverridesPlatformPolicy()), nullptr); + policy_map.Set( + key::kCloudUserPolicyOverridesCloudMachinePolicy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, + base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr); + // Causes the stored metapolicy values to be updated. + PolicyMap policy_map_empty; + policy_map.MergeFrom(policy_map_empty); + + if (IsUserAffiliated()) { + base::flat_set<std::string> affiliation_ids; + affiliation_ids.insert("a"); + policy_map.SetUserAffiliationIds(affiliation_ids); + policy_map.SetDeviceAffiliationIds(affiliation_ids); + } + + CheckPriorityConditions(policy_map); +} + +INSTANTIATE_TEST_SUITE_P(PolicyMapPriorityTestInstance, + PolicyMapPriorityTest, + testing::Combine(testing::Values(false, true), + testing::Values(false, true), + testing::Values(false, true))); +#endif // !BUILDFLAG(IS_CHROMEOS) + +} // namespace policy |