diff options
Diffstat (limited to 'chromium/components/policy/core/common/schema_map_unittest.cc')
-rw-r--r-- | chromium/components/policy/core/common/schema_map_unittest.cc | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/chromium/components/policy/core/common/schema_map_unittest.cc b/chromium/components/policy/core/common/schema_map_unittest.cc new file mode 100644 index 00000000000..96b34e07fc3 --- /dev/null +++ b/chromium/components/policy/core/common/schema_map_unittest.cc @@ -0,0 +1,385 @@ +// 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/schema_map.h" +#include <memory> + +#include "base/memory/weak_ptr.h" +#include "base/values.h" +#include "components/policy/core/common/external_data_fetcher.h" +#include "components/policy/core/common/external_data_manager.h" +#include "components/policy/core/common/policy_bundle.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_types.h" +#include "components/policy/core/common/schema.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 { + +const char kTestSchema[] = + R"({ + "type": "object", + "properties": { + "string": { "type": "string" }, + "integer": { "type": "integer" }, + "boolean": { "type": "boolean" }, + "double": { "type": "number" }, + "list": { + "type": "array", + "items": { "type": "string" } + }, + "object": { + "type": "object", + "properties": { + "a": { "type": "string" }, + "b": { "type": "integer" } + } + } + } + })"; + +} // namespace + +class SchemaMapTest : public testing::Test { + protected: + Schema CreateTestSchema() { + std::string error; + Schema schema = Schema::Parse(kTestSchema, &error); + if (!schema.valid()) + ADD_FAILURE() << error; + return schema; + } + + scoped_refptr<SchemaMap> CreateTestMap() { + Schema schema = CreateTestSchema(); + ComponentMap component_map; + component_map["extension-1"] = schema; + component_map["extension-2"] = schema; + component_map["legacy-extension"] = Schema(); + + DomainMap domain_map; + domain_map[POLICY_DOMAIN_EXTENSIONS] = component_map; + + return new SchemaMap(std::move(domain_map)); + } +}; + +TEST_F(SchemaMapTest, Empty) { + scoped_refptr<SchemaMap> map = new SchemaMap(); + EXPECT_TRUE(map->GetDomains().empty()); + EXPECT_FALSE(map->GetComponents(POLICY_DOMAIN_CHROME)); + EXPECT_FALSE(map->GetComponents(POLICY_DOMAIN_EXTENSIONS)); + EXPECT_FALSE(map->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""))); + EXPECT_FALSE(map->HasComponents()); +} + +TEST_F(SchemaMapTest, HasComponents) { + scoped_refptr<SchemaMap> map = new SchemaMap(); + EXPECT_FALSE(map->HasComponents()); + + // The Chrome schema does not count as a component. + Schema schema = CreateTestSchema(); + ComponentMap component_map; + component_map[""] = schema; + DomainMap domain_map; + domain_map[POLICY_DOMAIN_CHROME] = component_map; + map = new SchemaMap(std::move(domain_map)); + EXPECT_FALSE(map->HasComponents()); + + // An extension schema does. + domain_map.clear(); + domain_map[POLICY_DOMAIN_EXTENSIONS] = component_map; + map = new SchemaMap(std::move(domain_map)); + EXPECT_TRUE(map->HasComponents()); +} + +TEST_F(SchemaMapTest, Lookups) { + scoped_refptr<SchemaMap> map = CreateTestMap(); + ASSERT_TRUE(map.get()); + EXPECT_TRUE(map->HasComponents()); + + EXPECT_FALSE(map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_CHROME, ""))); + EXPECT_FALSE(map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_CHROME, "extension-1"))); + EXPECT_FALSE(map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_CHROME, "legacy-extension"))); + EXPECT_FALSE(map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, ""))); + EXPECT_FALSE(map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "extension-3"))); + + const Schema* schema = + map->GetSchema(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "extension-1")); + ASSERT_TRUE(schema); + EXPECT_TRUE(schema->valid()); + + schema = map->GetSchema( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "legacy-extension")); + ASSERT_TRUE(schema); + EXPECT_FALSE(schema->valid()); +} + +// Tests FilterBundle when |drop_invalid_component_policies| is set to true. +TEST_F(SchemaMapTest, FilterBundle) { + std::string error; + Schema schema = Schema::Parse(kTestSchema, &error); + ASSERT_TRUE(schema.valid()) << error; + + DomainMap domain_map; + domain_map[POLICY_DOMAIN_EXTENSIONS]["abc"] = schema; + scoped_refptr<SchemaMap> schema_map = new SchemaMap(std::move(domain_map)); + + PolicyBundle bundle; + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/true); + const PolicyBundle empty_bundle; + EXPECT_TRUE(bundle.Equals(empty_bundle)); + + // The Chrome namespace isn't filtered. + PolicyBundle expected_bundle; + PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, ""); + expected_bundle.Get(chrome_ns).Set("ChromePolicy", POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("value"), nullptr); + bundle.CopyFrom(expected_bundle); + + // Unknown components are filtered out. + PolicyNamespace another_extension_ns(POLICY_DOMAIN_EXTENSIONS, "xyz"); + bundle.Get(another_extension_ns) + .Set("AnotherExtensionPolicy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value"), nullptr); + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/true); + EXPECT_TRUE(bundle.Equals(expected_bundle)); + + PolicyNamespace extension_ns(POLICY_DOMAIN_EXTENSIONS, "abc"); + PolicyMap& map = expected_bundle.Get(extension_ns); + base::ListValue list; + list.Append("a"); + list.Append("b"); + map.Set("list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, list.Clone(), nullptr); + map.Set("boolean", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(true), nullptr); + map.Set("integer", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(1), nullptr); + map.Set("double", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(1.2), nullptr); + base::DictionaryValue dict; + dict.SetStringKey("a", "b"); + dict.SetIntKey("b", 2); + map.Set("object", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, dict.Clone(), nullptr); + map.Set("string", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value"), nullptr); + + bundle.MergeFrom(expected_bundle); + bundle.Get(extension_ns) + .Set("Unexpected", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("to-be-removed"), nullptr); + + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/true); + // Merged twice so this causes a conflict. + expected_bundle.Get(chrome_ns) + .GetMutable("ChromePolicy") + ->AddConflictingPolicy( + expected_bundle.Get(chrome_ns).Get("ChromePolicy")->DeepCopy()); + expected_bundle.Get(chrome_ns) + .GetMutable("ChromePolicy") + ->AddMessage(PolicyMap::MessageType::kInfo, + IDS_POLICY_CONFLICT_SAME_VALUE); + EXPECT_TRUE(bundle.Equals(expected_bundle)); + + // Mismatched types are also removed. + bundle.Clear(); + PolicyMap& badmap = bundle.Get(extension_ns); + badmap.Set("list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + badmap.Set("boolean", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(0), nullptr); + badmap.Set("integer", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + badmap.Set("null", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + badmap.Set("double", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + badmap.Set("object", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value(false), nullptr); + badmap.Set("string", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, absl::nullopt, + std::make_unique<ExternalDataFetcher>(nullptr, std::string())); + + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/true); + EXPECT_TRUE(bundle.Equals(empty_bundle)); +} + +// Tests FilterBundle when |drop_invalid_component_policies| is set to true. +TEST_F(SchemaMapTest, LegacyComponents) { + std::string error; + Schema schema = Schema::Parse( + R"({ + "type": "object", + "properties": { + "String": { "type": "string" } + } + })", + &error); + ASSERT_TRUE(schema.valid()) << error; + + DomainMap domain_map; + domain_map[POLICY_DOMAIN_EXTENSIONS]["with-schema"] = schema; + domain_map[POLICY_DOMAIN_EXTENSIONS]["without-schema"] = Schema(); + scoped_refptr<SchemaMap> schema_map = new SchemaMap(std::move(domain_map)); + + // |bundle| contains policies loaded by a policy provider. + PolicyBundle bundle; + + // Known components with schemas are filtered. + PolicyNamespace extension_ns(POLICY_DOMAIN_EXTENSIONS, "with-schema"); + bundle.Get(extension_ns) + .Set("String", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 1"), nullptr); + + // The Chrome namespace isn't filtered. + PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, ""); + bundle.Get(chrome_ns).Set("ChromePolicy", POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("value 3"), nullptr); + + PolicyBundle expected_bundle; + expected_bundle.MergeFrom(bundle); + + // Known components without a schema are filtered out completely. + PolicyNamespace without_schema_ns(POLICY_DOMAIN_EXTENSIONS, "without-schema"); + bundle.Get(without_schema_ns) + .Set("Schemaless", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 2"), nullptr); + + // Unknown policies of known components with a schema are removed when + // |drop_invalid_component_policies| is true in the FilterBundle call. + bundle.Get(extension_ns) + .Set("Surprise", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 4"), nullptr); + + // Unknown components are removed. + PolicyNamespace unknown_ns(POLICY_DOMAIN_EXTENSIONS, "unknown"); + bundle.Get(unknown_ns) + .Set("Surprise", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 5"), nullptr); + + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/true); + EXPECT_TRUE(bundle.Equals(expected_bundle)); +} + +// Tests FilterBundle when |drop_invalid_component_policies| is set to false. +TEST_F(SchemaMapTest, FilterBundleInvalidatesPolicies) { + std::string error; + Schema schema = Schema::Parse( + R"({ + "type": "object", + "properties": { + "String": { "type": "string" } + } + })", + &error); + ASSERT_TRUE(schema.valid()) << error; + + DomainMap domain_map; + domain_map[POLICY_DOMAIN_EXTENSIONS]["with-schema"] = schema; + domain_map[POLICY_DOMAIN_EXTENSIONS]["without-schema"] = Schema(); + scoped_refptr<SchemaMap> schema_map = new SchemaMap(std::move(domain_map)); + + // |bundle| contains policies loaded by a policy provider. + PolicyBundle bundle; + + // Known components with schemas are filtered. + PolicyNamespace extension_ns(POLICY_DOMAIN_EXTENSIONS, "with-schema"); + bundle.Get(extension_ns) + .Set("String", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 1"), nullptr); + + // The Chrome namespace isn't filtered. + PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, ""); + bundle.Get(chrome_ns).Set("ChromePolicy", POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("value 3"), nullptr); + + // Unknown policies of known components with a schema are invalidated when + // |drop_invalid_component_policies| is false in the FilterBundle call. + bundle.Get(extension_ns) + .Set("Surprise", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 4"), nullptr); + + // Known components without a schema are also invalidated. + PolicyNamespace without_schema_ns(POLICY_DOMAIN_EXTENSIONS, "without-schema"); + bundle.Get(without_schema_ns) + .Set("Schemaless", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 2"), nullptr); + + PolicyBundle expected_bundle; + expected_bundle.MergeFrom(bundle); + // Two policies will be invalidated. + expected_bundle.Get(extension_ns).GetMutable("Surprise")->SetInvalid(); + expected_bundle.Get(without_schema_ns).GetMutable("Schemaless")->SetInvalid(); + + // Unknown components are removed. + PolicyNamespace unknown_ns(POLICY_DOMAIN_EXTENSIONS, "unknown"); + bundle.Get(unknown_ns) + .Set("Surprise", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, base::Value("value 5"), nullptr); + + // Get a reference to the policies that will be invalidated now, since it can + // no longer be accessed with Get() after being invalidated. + const PolicyMap::Entry* invalid_policy_entry_1 = + bundle.Get(extension_ns).Get("Surprise"); + ASSERT_TRUE(invalid_policy_entry_1); + const PolicyMap::Entry* invalid_policy_entry_2 = + bundle.Get(without_schema_ns).Get("Schemaless"); + ASSERT_TRUE(invalid_policy_entry_2); + + schema_map->FilterBundle(&bundle, /*drop_invalid_component_policies=*/false); + EXPECT_TRUE(bundle.Equals(expected_bundle)); + EXPECT_TRUE(invalid_policy_entry_1->ignored()); + EXPECT_TRUE(invalid_policy_entry_2->ignored()); +} + +TEST_F(SchemaMapTest, GetChanges) { + DomainMap map; + map[POLICY_DOMAIN_CHROME][""] = Schema(); + scoped_refptr<SchemaMap> older = new SchemaMap(std::move(map)); + map.clear(); + map[POLICY_DOMAIN_CHROME][""] = Schema(); + scoped_refptr<SchemaMap> newer = new SchemaMap(std::move(map)); + + PolicyNamespaceList removed; + PolicyNamespaceList added; + newer->GetChanges(older, &removed, &added); + EXPECT_TRUE(removed.empty()); + EXPECT_TRUE(added.empty()); + + map.clear(); + map[POLICY_DOMAIN_CHROME][""] = Schema(); + map[POLICY_DOMAIN_EXTENSIONS]["xyz"] = Schema(); + newer = new SchemaMap(std::move(map)); + newer->GetChanges(older, &removed, &added); + EXPECT_TRUE(removed.empty()); + ASSERT_EQ(1u, added.size()); + EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz"), added[0]); + + older = newer; + map.clear(); + map[POLICY_DOMAIN_EXTENSIONS]["abc"] = Schema(); + newer = new SchemaMap(std::move(map)); + newer->GetChanges(older, &removed, &added); + ASSERT_EQ(2u, removed.size()); + EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_CHROME, ""), removed[0]); + EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz"), removed[1]); + ASSERT_EQ(1u, added.size()); + EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), added[0]); +} + +} // namespace policy |