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.
5 #include "components/policy/core/common/schema_map.h"
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"
20 const char kTestSchema
[] =
22 " \"type\": \"object\","
24 " \"string\": { \"type\": \"string\" },"
25 " \"integer\": { \"type\": \"integer\" },"
26 " \"boolean\": { \"type\": \"boolean\" },"
27 " \"null\": { \"type\": \"null\" },"
28 " \"double\": { \"type\": \"number\" },"
30 " \"type\": \"array\","
31 " \"items\": { \"type\": \"string\" }"
34 " \"type\": \"object\","
36 " \"a\": { \"type\": \"string\" },"
37 " \"b\": { \"type\": \"integer\" }"
45 class SchemaMapTest
: public testing::Test
{
47 Schema
CreateTestSchema() {
49 Schema schema
= Schema::Parse(kTestSchema
, &error
);
51 ADD_FAILURE() << error
;
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();
63 domain_map
[POLICY_DOMAIN_EXTENSIONS
] = component_map
;
65 return new SchemaMap(domain_map
);
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());
78 TEST_F(SchemaMapTest
, HasComponents
) {
79 scoped_refptr
<SchemaMap
> map
= new SchemaMap();
80 EXPECT_FALSE(map
->HasComponents());
82 // The Chrome schema does not count as a component.
83 Schema schema
= CreateTestSchema();
84 ComponentMap component_map
;
85 component_map
[""] = schema
;
87 domain_map
[POLICY_DOMAIN_CHROME
] = component_map
;
88 map
= new SchemaMap(domain_map
);
89 EXPECT_FALSE(map
->HasComponents());
91 // An extension schema does.
92 domain_map
[POLICY_DOMAIN_EXTENSIONS
] = component_map
;
93 map
= new SchemaMap(domain_map
);
94 EXPECT_TRUE(map
->HasComponents());
97 TEST_F(SchemaMapTest
, Lookups
) {
98 scoped_refptr
<SchemaMap
> map
= CreateTestMap();
100 EXPECT_TRUE(map
->HasComponents());
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")));
113 const Schema
* schema
=
114 map
->GetSchema(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS
, "extension-1"));
116 EXPECT_TRUE(schema
->valid());
118 schema
= map
->GetSchema(
119 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS
, "legacy-extension"));
121 EXPECT_FALSE(schema
->valid());
124 TEST_F(SchemaMapTest
, FilterBundle
) {
126 Schema schema
= Schema::Parse(kTestSchema
, &error
);
127 ASSERT_TRUE(schema
.valid()) << error
;
129 DomainMap domain_map
;
130 domain_map
[POLICY_DOMAIN_EXTENSIONS
]["abc"] = schema
;
131 scoped_refptr
<SchemaMap
> schema_map
= new SchemaMap(domain_map
);
134 schema_map
->FilterBundle(&bundle
);
135 const PolicyBundle empty_bundle
;
136 EXPECT_TRUE(bundle
.Equals(empty_bundle
));
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
,
144 base::Value::CreateStringValue("value"),
146 bundle
.CopyFrom(expected_bundle
);
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
,
154 base::Value::CreateStringValue("value"),
156 schema_map
->FilterBundle(&bundle
);
157 EXPECT_TRUE(bundle
.Equals(expected_bundle
));
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
);
182 bundle
.MergeFrom(expected_bundle
);
183 bundle
.Get(extension_ns
).Set("Unexpected",
184 POLICY_LEVEL_MANDATORY
,
186 base::Value::CreateStringValue("to-be-removed"),
189 schema_map
->FilterBundle(&bundle
);
190 EXPECT_TRUE(bundle
.Equals(expected_bundle
));
192 // Mismatched types are also removed.
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
,
209 new ExternalDataFetcher(base::WeakPtr
<ExternalDataManager
>(),
212 schema_map
->FilterBundle(&bundle
);
213 EXPECT_TRUE(bundle
.Equals(empty_bundle
));
216 TEST_F(SchemaMapTest
, LegacyComponents
) {
218 Schema schema
= Schema::Parse(
220 " \"type\":\"object\","
222 " \"String\": { \"type\": \"string\" }"
225 ASSERT_TRUE(schema
.valid()) << error
;
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
);
232 // |bundle| contains policies loaded by a policy provider.
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
,
240 base::Value::CreateStringValue("value 1"),
243 // Known components without a schema are not filtered.
244 PolicyNamespace
without_schema_ns(POLICY_DOMAIN_EXTENSIONS
, "without-schema");
245 bundle
.Get(without_schema_ns
).Set("Schemaless",
246 POLICY_LEVEL_MANDATORY
,
248 base::Value::CreateStringValue("value 2"),
251 // The Chrome namespace isn't filtered.
252 PolicyNamespace
chrome_ns(POLICY_DOMAIN_CHROME
, "");
253 bundle
.Get(chrome_ns
).Set("ChromePolicy",
254 POLICY_LEVEL_MANDATORY
,
256 base::Value::CreateStringValue("value 3"),
259 PolicyBundle expected_bundle
;
260 expected_bundle
.MergeFrom(bundle
);
262 // Unknown policies of known components with a schema are removed.
263 bundle
.Get(extension_ns
).Set("Surprise",
264 POLICY_LEVEL_MANDATORY
,
266 base::Value::CreateStringValue("value 4"),
269 // Unknown components are removed.
270 PolicyNamespace
unknown_ns(POLICY_DOMAIN_EXTENSIONS
, "unknown");
271 bundle
.Get(unknown_ns
).Set("Surprise",
272 POLICY_LEVEL_MANDATORY
,
274 base::Value::CreateStringValue("value 5"),
277 schema_map
->FilterBundle(&bundle
);
278 EXPECT_TRUE(bundle
.Equals(expected_bundle
));
281 TEST_F(SchemaMapTest
, GetChanges
) {
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
);
288 PolicyNamespaceList removed
;
289 PolicyNamespaceList added
;
290 newer
->GetChanges(older
, &removed
, &added
);
291 EXPECT_TRUE(removed
.empty());
292 EXPECT_TRUE(added
.empty());
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]);
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]);
313 } // namespace policy