Home | History | Annotate | Download | only in common
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/policy/core/common/schema_map.h"
      6 
      7 #include "base/memory/weak_ptr.h"
      8 #include "base/values.h"
      9 #include "components/policy/core/common/external_data_fetcher.h"
     10 #include "components/policy/core/common/external_data_manager.h"
     11 #include "components/policy/core/common/policy_bundle.h"
     12 #include "components/policy/core/common/policy_map.h"
     13 #include "components/policy/core/common/schema.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace policy {
     17 
     18 namespace {
     19 
     20 const char kTestSchema[] =
     21     "{"
     22     "  \"type\": \"object\","
     23     "  \"properties\": {"
     24     "    \"string\": { \"type\": \"string\" },"
     25     "    \"integer\": { \"type\": \"integer\" },"
     26     "    \"boolean\": { \"type\": \"boolean\" },"
     27     "    \"null\": { \"type\": \"null\" },"
     28     "    \"double\": { \"type\": \"number\" },"
     29     "    \"list\": {"
     30     "      \"type\": \"array\","
     31     "      \"items\": { \"type\": \"string\" }"
     32     "    },"
     33     "    \"object\": {"
     34     "      \"type\": \"object\","
     35     "      \"properties\": {"
     36     "        \"a\": { \"type\": \"string\" },"
     37     "        \"b\": { \"type\": \"integer\" }"
     38     "      }"
     39     "    }"
     40     "  }"
     41     "}";
     42 
     43 }  // namespace
     44 
     45 class SchemaMapTest : public testing::Test {
     46  protected:
     47   Schema CreateTestSchema() {
     48     std::string error;
     49     Schema schema = Schema::Parse(kTestSchema, &error);
     50     if (!schema.valid())
     51       ADD_FAILURE() << error;
     52     return schema;
     53   }
     54 
     55   scoped_refptr<SchemaMap> CreateTestMap() {
     56     Schema schema = CreateTestSchema();
     57     ComponentMap component_map;
     58     component_map["extension-1"] = schema;
     59     component_map["extension-2"] = schema;
     60     component_map["legacy-extension"] = Schema();
     61 
     62     DomainMap domain_map;
     63     domain_map[POLICY_DOMAIN_EXTENSIONS] = component_map;
     64 
     65     return new SchemaMap(domain_map);
     66   }
     67 };
     68 
     69 TEST_F(SchemaMapTest, Empty) {
     70   scoped_refptr<SchemaMap> map = new SchemaMap();
     71   EXPECT_TRUE(map->GetDomains().empty());
     72   EXPECT_FALSE(map->GetComponents(POLICY_DOMAIN_CHROME));
     73   EXPECT_FALSE(map->GetComponents(POLICY_DOMAIN_EXTENSIONS));
     74   EXPECT_FALSE(map->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, "")));
     75   EXPECT_FALSE(map->HasComponents());
     76 }
     77 
     78 TEST_F(SchemaMapTest, HasComponents) {
     79   scoped_refptr<SchemaMap> map = new SchemaMap();
     80   EXPECT_FALSE(map->HasComponents());
     81 
     82   // The Chrome schema does not count as a component.
     83   Schema schema = CreateTestSchema();
     84   ComponentMap component_map;
     85   component_map[""] = schema;
     86   DomainMap domain_map;
     87   domain_map[POLICY_DOMAIN_CHROME] = component_map;
     88   map = new SchemaMap(domain_map);
     89   EXPECT_FALSE(map->HasComponents());
     90 
     91   // An extension schema does.
     92   domain_map[POLICY_DOMAIN_EXTENSIONS] = component_map;
     93   map = new SchemaMap(domain_map);
     94   EXPECT_TRUE(map->HasComponents());
     95 }
     96 
     97 TEST_F(SchemaMapTest, Lookups) {
     98   scoped_refptr<SchemaMap> map = CreateTestMap();
     99   ASSERT_TRUE(map);
    100   EXPECT_TRUE(map->HasComponents());
    101 
    102   EXPECT_FALSE(map->GetSchema(
    103       PolicyNamespace(POLICY_DOMAIN_CHROME, "")));
    104   EXPECT_FALSE(map->GetSchema(
    105       PolicyNamespace(POLICY_DOMAIN_CHROME, "extension-1")));
    106   EXPECT_FALSE(map->GetSchema(
    107       PolicyNamespace(POLICY_DOMAIN_CHROME, "legacy-extension")));
    108   EXPECT_FALSE(map->GetSchema(
    109       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "")));
    110   EXPECT_FALSE(map->GetSchema(
    111       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "extension-3")));
    112 
    113   const Schema* schema =
    114       map->GetSchema(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "extension-1"));
    115   ASSERT_TRUE(schema);
    116   EXPECT_TRUE(schema->valid());
    117 
    118   schema = map->GetSchema(
    119       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "legacy-extension"));
    120   ASSERT_TRUE(schema);
    121   EXPECT_FALSE(schema->valid());
    122 }
    123 
    124 TEST_F(SchemaMapTest, FilterBundle) {
    125   std::string error;
    126   Schema schema = Schema::Parse(kTestSchema, &error);
    127   ASSERT_TRUE(schema.valid()) << error;
    128 
    129   DomainMap domain_map;
    130   domain_map[POLICY_DOMAIN_EXTENSIONS]["abc"] = schema;
    131   scoped_refptr<SchemaMap> schema_map = new SchemaMap(domain_map);
    132 
    133   PolicyBundle bundle;
    134   schema_map->FilterBundle(&bundle);
    135   const PolicyBundle empty_bundle;
    136   EXPECT_TRUE(bundle.Equals(empty_bundle));
    137 
    138   // The Chrome namespace isn't filtered.
    139   PolicyBundle expected_bundle;
    140   PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, "");
    141   expected_bundle.Get(chrome_ns).Set("ChromePolicy",
    142                                      POLICY_LEVEL_MANDATORY,
    143                                      POLICY_SCOPE_USER,
    144                                      base::Value::CreateStringValue("value"),
    145                                      NULL);
    146   bundle.CopyFrom(expected_bundle);
    147 
    148   // Unknown components are filtered out.
    149   PolicyNamespace another_extension_ns(POLICY_DOMAIN_EXTENSIONS, "xyz");
    150   bundle.Get(another_extension_ns).Set(
    151       "AnotherExtensionPolicy",
    152       POLICY_LEVEL_MANDATORY,
    153       POLICY_SCOPE_USER,
    154       base::Value::CreateStringValue("value"),
    155       NULL);
    156   schema_map->FilterBundle(&bundle);
    157   EXPECT_TRUE(bundle.Equals(expected_bundle));
    158 
    159   PolicyNamespace extension_ns(POLICY_DOMAIN_EXTENSIONS, "abc");
    160   PolicyMap& map = expected_bundle.Get(extension_ns);
    161   base::ListValue list;
    162   list.AppendString("a");
    163   list.AppendString("b");
    164   map.Set("list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    165           list.DeepCopy(), NULL);
    166   map.Set("boolean", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    167           base::Value::CreateBooleanValue(true), NULL);
    168   map.Set("integer", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    169           base::Value::CreateIntegerValue(1), NULL);
    170   map.Set("null", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    171           base::Value::CreateNullValue(), NULL);
    172   map.Set("double", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    173           base::Value::CreateDoubleValue(1.2), NULL);
    174   base::DictionaryValue dict;
    175   dict.SetString("a", "b");
    176   dict.SetInteger("b", 2);
    177   map.Set("object", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    178           dict.DeepCopy(), NULL);
    179   map.Set("string", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    180           base::Value::CreateStringValue("value"), NULL);
    181 
    182   bundle.MergeFrom(expected_bundle);
    183   bundle.Get(extension_ns).Set("Unexpected",
    184                                POLICY_LEVEL_MANDATORY,
    185                                POLICY_SCOPE_USER,
    186                                base::Value::CreateStringValue("to-be-removed"),
    187                                NULL);
    188 
    189   schema_map->FilterBundle(&bundle);
    190   EXPECT_TRUE(bundle.Equals(expected_bundle));
    191 
    192   // Mismatched types are also removed.
    193   bundle.Clear();
    194   PolicyMap& badmap = bundle.Get(extension_ns);
    195   badmap.Set("list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    196              base::Value::CreateBooleanValue(false), NULL);
    197   badmap.Set("boolean", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    198              base::Value::CreateIntegerValue(0), NULL);
    199   badmap.Set("integer", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    200              base::Value::CreateBooleanValue(false), NULL);
    201   badmap.Set("null", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    202              base::Value::CreateBooleanValue(false), NULL);
    203   badmap.Set("double", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    204              base::Value::CreateBooleanValue(false), NULL);
    205   badmap.Set("object", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    206              base::Value::CreateBooleanValue(false), NULL);
    207   badmap.Set("string", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    208              NULL,
    209              new ExternalDataFetcher(base::WeakPtr<ExternalDataManager>(),
    210                                      std::string()));
    211 
    212   schema_map->FilterBundle(&bundle);
    213   EXPECT_TRUE(bundle.Equals(empty_bundle));
    214 }
    215 
    216 TEST_F(SchemaMapTest, LegacyComponents) {
    217   std::string error;
    218   Schema schema = Schema::Parse(
    219       "{"
    220       "  \"type\":\"object\","
    221       "  \"properties\": {"
    222       "    \"String\": { \"type\": \"string\" }"
    223       "  }"
    224       "}", &error);
    225   ASSERT_TRUE(schema.valid()) << error;
    226 
    227   DomainMap domain_map;
    228   domain_map[POLICY_DOMAIN_EXTENSIONS]["with-schema"] = schema;
    229   domain_map[POLICY_DOMAIN_EXTENSIONS]["without-schema"] = Schema();
    230   scoped_refptr<SchemaMap> schema_map = new SchemaMap(domain_map);
    231 
    232   // |bundle| contains policies loaded by a policy provider.
    233   PolicyBundle bundle;
    234 
    235   // Known components with schemas are filtered.
    236   PolicyNamespace extension_ns(POLICY_DOMAIN_EXTENSIONS, "with-schema");
    237   bundle.Get(extension_ns).Set("String",
    238                                POLICY_LEVEL_MANDATORY,
    239                                POLICY_SCOPE_USER,
    240                                base::Value::CreateStringValue("value 1"),
    241                                NULL);
    242 
    243   // The Chrome namespace isn't filtered.
    244   PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, "");
    245   bundle.Get(chrome_ns).Set("ChromePolicy",
    246                             POLICY_LEVEL_MANDATORY,
    247                             POLICY_SCOPE_USER,
    248                             base::Value::CreateStringValue("value 3"),
    249                             NULL);
    250 
    251   PolicyBundle expected_bundle;
    252   expected_bundle.MergeFrom(bundle);
    253 
    254   // Known components without a schema are filtered out completely.
    255   PolicyNamespace without_schema_ns(POLICY_DOMAIN_EXTENSIONS, "without-schema");
    256   bundle.Get(without_schema_ns).Set("Schemaless",
    257                                     POLICY_LEVEL_MANDATORY,
    258                                     POLICY_SCOPE_USER,
    259                                     base::Value::CreateStringValue("value 2"),
    260                                     NULL);
    261 
    262   // Unknown policies of known components with a schema are removed.
    263   bundle.Get(extension_ns).Set("Surprise",
    264                                POLICY_LEVEL_MANDATORY,
    265                                POLICY_SCOPE_USER,
    266                                base::Value::CreateStringValue("value 4"),
    267                                NULL);
    268 
    269   // Unknown components are removed.
    270   PolicyNamespace unknown_ns(POLICY_DOMAIN_EXTENSIONS, "unknown");
    271   bundle.Get(unknown_ns).Set("Surprise",
    272                              POLICY_LEVEL_MANDATORY,
    273                              POLICY_SCOPE_USER,
    274                              base::Value::CreateStringValue("value 5"),
    275                              NULL);
    276 
    277   schema_map->FilterBundle(&bundle);
    278   EXPECT_TRUE(bundle.Equals(expected_bundle));
    279 }
    280 
    281 TEST_F(SchemaMapTest, GetChanges) {
    282   DomainMap map;
    283   map[POLICY_DOMAIN_CHROME][""] = Schema();
    284   scoped_refptr<SchemaMap> older = new SchemaMap(map);
    285   map[POLICY_DOMAIN_CHROME][""] = Schema();
    286   scoped_refptr<SchemaMap> newer = new SchemaMap(map);
    287 
    288   PolicyNamespaceList removed;
    289   PolicyNamespaceList added;
    290   newer->GetChanges(older, &removed, &added);
    291   EXPECT_TRUE(removed.empty());
    292   EXPECT_TRUE(added.empty());
    293 
    294   map[POLICY_DOMAIN_CHROME][""] = Schema();
    295   map[POLICY_DOMAIN_EXTENSIONS]["xyz"] = Schema();
    296   newer = new SchemaMap(map);
    297   newer->GetChanges(older, &removed, &added);
    298   EXPECT_TRUE(removed.empty());
    299   ASSERT_EQ(1u, added.size());
    300   EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz"), added[0]);
    301 
    302   older = newer;
    303   map[POLICY_DOMAIN_EXTENSIONS]["abc"] = Schema();
    304   newer = new SchemaMap(map);
    305   newer->GetChanges(older, &removed, &added);
    306   ASSERT_EQ(2u, removed.size());
    307   EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_CHROME, ""), removed[0]);
    308   EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz"), removed[1]);
    309   ASSERT_EQ(1u, added.size());
    310   EXPECT_EQ(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), added[0]);
    311 }
    312 
    313 }  // namespace policy
    314