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/configuration_policy_provider_test.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/values.h"
11 #include "components/policy/core/common/configuration_policy_provider.h"
12 #include "components/policy/core/common/external_data_fetcher.h"
13 #include "components/policy/core/common/mock_configuration_policy_provider.h"
14 #include "components/policy/core/common/policy_bundle.h"
15 #include "components/policy/core/common/policy_map.h"
16 #include "components/policy/core/common/policy_namespace.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18
19 using ::testing::Mock;
20 using ::testing::_;
21
22 namespace policy {
23
24 const char kTestChromeSchema[] =
25 "{"
26 " \"type\": \"object\","
27 " \"properties\": {"
28 " \"StringPolicy\": { \"type\": \"string\" },"
29 " \"BooleanPolicy\": { \"type\": \"boolean\" },"
30 " \"IntegerPolicy\": { \"type\": \"integer\" },"
31 " \"StringListPolicy\": {"
32 " \"type\": \"array\","
33 " \"items\": { \"type\": \"string\" }"
34 " },"
35 " \"DictionaryPolicy\": {"
36 " \"type\": \"object\","
37 " \"properties\": {"
38 " \"bool\": { \"type\": \"boolean\" },"
39 " \"double\": { \"type\": \"number\" },"
40 " \"int\": { \"type\": \"integer\" },"
41 " \"string\": { \"type\": \"string\" },"
42 " \"array\": {"
43 " \"type\": \"array\","
44 " \"items\": { \"type\": \"string\" }"
45 " },"
46 " \"dictionary\": {"
47 " \"type\": \"object\","
48 " \"properties\": {"
49 " \"sub\": { \"type\": \"string\" },"
50 " \"sublist\": {"
51 " \"type\": \"array\","
52 " \"items\": {"
53 " \"type\": \"object\","
54 " \"properties\": {"
55 " \"aaa\": { \"type\": \"integer\" },"
56 " \"bbb\": { \"type\": \"integer\" },"
57 " \"ccc\": { \"type\": \"string\" },"
58 " \"ddd\": { \"type\": \"string\" }"
59 " }"
60 " }"
61 " }"
62 " }"
63 " },"
64 " \"list\": {"
65 " \"type\": \"array\","
66 " \"items\": {"
67 " \"type\": \"object\","
68 " \"properties\": {"
69 " \"subdictindex\": { \"type\": \"integer\" },"
70 " \"subdict\": {"
71 " \"type\": \"object\","
72 " \"properties\": {"
73 " \"bool\": { \"type\": \"boolean\" },"
74 " \"double\": { \"type\": \"number\" },"
75 " \"int\": { \"type\": \"integer\" },"
76 " \"string\": { \"type\": \"string\" }"
77 " }"
78 " }"
79 " }"
80 " }"
81 " },"
82 " \"dict\": {"
83 " \"type\": \"object\","
84 " \"properties\": {"
85 " \"bool\": { \"type\": \"boolean\" },"
86 " \"double\": { \"type\": \"number\" },"
87 " \"int\": { \"type\": \"integer\" },"
88 " \"string\": { \"type\": \"string\" },"
89 " \"list\": {"
90 " \"type\": \"array\","
91 " \"items\": {"
92 " \"type\": \"object\","
93 " \"properties\": {"
94 " \"subdictindex\": { \"type\": \"integer\" },"
95 " \"subdict\": {"
96 " \"type\": \"object\","
97 " \"properties\": {"
98 " \"bool\": { \"type\": \"boolean\" },"
99 " \"double\": { \"type\": \"number\" },"
100 " \"int\": { \"type\": \"integer\" },"
101 " \"string\": { \"type\": \"string\" }"
102 " }"
103 " }"
104 " }"
105 " }"
106 " }"
107 " }"
108 " }"
109 " }"
110 " }"
111 " }"
112 "}";
113
114 namespace test_keys {
115
116 const char kKeyString[] = "StringPolicy";
117 const char kKeyBoolean[] = "BooleanPolicy";
118 const char kKeyInteger[] = "IntegerPolicy";
119 const char kKeyStringList[] = "StringListPolicy";
120 const char kKeyDictionary[] = "DictionaryPolicy";
121
122 } // namespace test_keys
123
PolicyTestBase()124 PolicyTestBase::PolicyTestBase() {}
125
~PolicyTestBase()126 PolicyTestBase::~PolicyTestBase() {}
127
SetUp()128 void PolicyTestBase::SetUp() {
129 const PolicyNamespace ns(POLICY_DOMAIN_CHROME, "");
130 ASSERT_TRUE(RegisterSchema(ns, kTestChromeSchema));
131 }
132
TearDown()133 void PolicyTestBase::TearDown() {
134 loop_.RunUntilIdle();
135 }
136
RegisterSchema(const PolicyNamespace & ns,const std::string & schema_string)137 bool PolicyTestBase::RegisterSchema(const PolicyNamespace& ns,
138 const std::string& schema_string) {
139 std::string error;
140 Schema schema = Schema::Parse(schema_string, &error);
141 if (schema.valid()) {
142 schema_registry_.RegisterComponent(ns, schema);
143 return true;
144 }
145 ADD_FAILURE() << error;
146 return false;
147 }
148
PolicyProviderTestHarness(PolicyLevel level,PolicyScope scope)149 PolicyProviderTestHarness::PolicyProviderTestHarness(PolicyLevel level,
150 PolicyScope scope)
151 : level_(level), scope_(scope) {}
152
~PolicyProviderTestHarness()153 PolicyProviderTestHarness::~PolicyProviderTestHarness() {}
154
policy_level() const155 PolicyLevel PolicyProviderTestHarness::policy_level() const {
156 return level_;
157 }
158
policy_scope() const159 PolicyScope PolicyProviderTestHarness::policy_scope() const {
160 return scope_;
161 }
162
Install3rdPartyPolicy(const base::DictionaryValue * policies)163 void PolicyProviderTestHarness::Install3rdPartyPolicy(
164 const base::DictionaryValue* policies) {
165 FAIL();
166 }
167
ConfigurationPolicyProviderTest()168 ConfigurationPolicyProviderTest::ConfigurationPolicyProviderTest() {}
169
~ConfigurationPolicyProviderTest()170 ConfigurationPolicyProviderTest::~ConfigurationPolicyProviderTest() {}
171
SetUp()172 void ConfigurationPolicyProviderTest::SetUp() {
173 PolicyTestBase::SetUp();
174
175 test_harness_.reset((*GetParam())());
176 test_harness_->SetUp();
177
178 const PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, "");
179 Schema chrome_schema = *schema_registry_.schema_map()->GetSchema(chrome_ns);
180 Schema extension_schema =
181 chrome_schema.GetKnownProperty(test_keys::kKeyDictionary);
182 ASSERT_TRUE(extension_schema.valid());
183 schema_registry_.RegisterComponent(
184 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
185 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
186 extension_schema);
187 schema_registry_.RegisterComponent(
188 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
189 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
190 extension_schema);
191 schema_registry_.RegisterComponent(
192 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
193 "cccccccccccccccccccccccccccccccc"),
194 extension_schema);
195
196 provider_.reset(test_harness_->CreateProvider(&schema_registry_,
197 loop_.message_loop_proxy()));
198 provider_->Init(&schema_registry_);
199 // Some providers do a reload on init. Make sure any notifications generated
200 // are fired now.
201 loop_.RunUntilIdle();
202
203 const PolicyBundle kEmptyBundle;
204 EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
205 }
206
TearDown()207 void ConfigurationPolicyProviderTest::TearDown() {
208 // Give providers the chance to clean up after themselves on the file thread.
209 provider_->Shutdown();
210 provider_.reset();
211
212 PolicyTestBase::TearDown();
213 }
214
CheckValue(const char * policy_name,const base::Value & expected_value,base::Closure install_value)215 void ConfigurationPolicyProviderTest::CheckValue(
216 const char* policy_name,
217 const base::Value& expected_value,
218 base::Closure install_value) {
219 // Install the value, reload policy and check the provider for the value.
220 install_value.Run();
221 provider_->RefreshPolicies();
222 loop_.RunUntilIdle();
223 PolicyBundle expected_bundle;
224 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
225 .Set(policy_name,
226 test_harness_->policy_level(),
227 test_harness_->policy_scope(),
228 expected_value.DeepCopy(),
229 NULL);
230 EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
231 // TODO(joaodasilva): set the policy in the POLICY_DOMAIN_EXTENSIONS too,
232 // and extend the |expected_bundle|, once all providers are ready.
233 }
234
TEST_P(ConfigurationPolicyProviderTest,Empty)235 TEST_P(ConfigurationPolicyProviderTest, Empty) {
236 provider_->RefreshPolicies();
237 loop_.RunUntilIdle();
238 const PolicyBundle kEmptyBundle;
239 EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
240 }
241
TEST_P(ConfigurationPolicyProviderTest,StringValue)242 TEST_P(ConfigurationPolicyProviderTest, StringValue) {
243 const char kTestString[] = "string_value";
244 base::StringValue expected_value(kTestString);
245 CheckValue(test_keys::kKeyString,
246 expected_value,
247 base::Bind(&PolicyProviderTestHarness::InstallStringPolicy,
248 base::Unretained(test_harness_.get()),
249 test_keys::kKeyString,
250 kTestString));
251 }
252
TEST_P(ConfigurationPolicyProviderTest,BooleanValue)253 TEST_P(ConfigurationPolicyProviderTest, BooleanValue) {
254 base::FundamentalValue expected_value(true);
255 CheckValue(test_keys::kKeyBoolean,
256 expected_value,
257 base::Bind(&PolicyProviderTestHarness::InstallBooleanPolicy,
258 base::Unretained(test_harness_.get()),
259 test_keys::kKeyBoolean,
260 true));
261 }
262
TEST_P(ConfigurationPolicyProviderTest,IntegerValue)263 TEST_P(ConfigurationPolicyProviderTest, IntegerValue) {
264 base::FundamentalValue expected_value(42);
265 CheckValue(test_keys::kKeyInteger,
266 expected_value,
267 base::Bind(&PolicyProviderTestHarness::InstallIntegerPolicy,
268 base::Unretained(test_harness_.get()),
269 test_keys::kKeyInteger,
270 42));
271 }
272
TEST_P(ConfigurationPolicyProviderTest,StringListValue)273 TEST_P(ConfigurationPolicyProviderTest, StringListValue) {
274 base::ListValue expected_value;
275 expected_value.Set(0U, new base::StringValue("first"));
276 expected_value.Set(1U, new base::StringValue("second"));
277 CheckValue(test_keys::kKeyStringList,
278 expected_value,
279 base::Bind(&PolicyProviderTestHarness::InstallStringListPolicy,
280 base::Unretained(test_harness_.get()),
281 test_keys::kKeyStringList,
282 &expected_value));
283 }
284
TEST_P(ConfigurationPolicyProviderTest,DictionaryValue)285 TEST_P(ConfigurationPolicyProviderTest, DictionaryValue) {
286 base::DictionaryValue expected_value;
287 expected_value.SetBoolean("bool", true);
288 expected_value.SetDouble("double", 123.456);
289 expected_value.SetInteger("int", 123);
290 expected_value.SetString("string", "omg");
291
292 base::ListValue* list = new base::ListValue();
293 list->Set(0U, new base::StringValue("first"));
294 list->Set(1U, new base::StringValue("second"));
295 expected_value.Set("array", list);
296
297 base::DictionaryValue* dict = new base::DictionaryValue();
298 dict->SetString("sub", "value");
299 list = new base::ListValue();
300 base::DictionaryValue* sub = new base::DictionaryValue();
301 sub->SetInteger("aaa", 111);
302 sub->SetInteger("bbb", 222);
303 list->Append(sub);
304 sub = new base::DictionaryValue();
305 sub->SetString("ccc", "333");
306 sub->SetString("ddd", "444");
307 list->Append(sub);
308 dict->Set("sublist", list);
309 expected_value.Set("dictionary", dict);
310
311 CheckValue(test_keys::kKeyDictionary,
312 expected_value,
313 base::Bind(&PolicyProviderTestHarness::InstallDictionaryPolicy,
314 base::Unretained(test_harness_.get()),
315 test_keys::kKeyDictionary,
316 &expected_value));
317 }
318
TEST_P(ConfigurationPolicyProviderTest,RefreshPolicies)319 TEST_P(ConfigurationPolicyProviderTest, RefreshPolicies) {
320 PolicyBundle bundle;
321 EXPECT_TRUE(provider_->policies().Equals(bundle));
322
323 // OnUpdatePolicy is called even when there are no changes.
324 MockConfigurationPolicyObserver observer;
325 provider_->AddObserver(&observer);
326 EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
327 provider_->RefreshPolicies();
328 loop_.RunUntilIdle();
329 Mock::VerifyAndClearExpectations(&observer);
330
331 EXPECT_TRUE(provider_->policies().Equals(bundle));
332
333 // OnUpdatePolicy is called when there are changes.
334 test_harness_->InstallStringPolicy(test_keys::kKeyString, "value");
335 EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
336 provider_->RefreshPolicies();
337 loop_.RunUntilIdle();
338 Mock::VerifyAndClearExpectations(&observer);
339
340 bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
341 .Set(test_keys::kKeyString,
342 test_harness_->policy_level(),
343 test_harness_->policy_scope(),
344 new base::StringValue("value"),
345 NULL);
346 EXPECT_TRUE(provider_->policies().Equals(bundle));
347 provider_->RemoveObserver(&observer);
348 }
349
350 Configuration3rdPartyPolicyProviderTest::
Configuration3rdPartyPolicyProviderTest()351 Configuration3rdPartyPolicyProviderTest() {}
352
353 Configuration3rdPartyPolicyProviderTest::
~Configuration3rdPartyPolicyProviderTest()354 ~Configuration3rdPartyPolicyProviderTest() {}
355
TEST_P(Configuration3rdPartyPolicyProviderTest,Load3rdParty)356 TEST_P(Configuration3rdPartyPolicyProviderTest, Load3rdParty) {
357 base::DictionaryValue policy_dict;
358 policy_dict.SetBoolean("bool", true);
359 policy_dict.SetDouble("double", 123.456);
360 policy_dict.SetInteger("int", 789);
361 policy_dict.SetString("string", "string value");
362
363 base::ListValue* list = new base::ListValue();
364 for (int i = 0; i < 2; ++i) {
365 base::DictionaryValue* dict = new base::DictionaryValue();
366 dict->SetInteger("subdictindex", i);
367 dict->Set("subdict", policy_dict.DeepCopy());
368 list->Append(dict);
369 }
370 policy_dict.Set("list", list);
371 policy_dict.Set("dict", policy_dict.DeepCopy());
372
373 // Install these policies as a Chrome policy.
374 test_harness_->InstallDictionaryPolicy(test_keys::kKeyDictionary,
375 &policy_dict);
376 // Install them as 3rd party policies too.
377 base::DictionaryValue policy_3rdparty;
378 policy_3rdparty.Set("extensions.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
379 policy_dict.DeepCopy());
380 policy_3rdparty.Set("extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
381 policy_dict.DeepCopy());
382 // Install invalid 3rd party policies that shouldn't be loaded. These also
383 // help detecting memory leaks in the code paths that detect invalid input.
384 policy_3rdparty.Set("invalid-domain.component", policy_dict.DeepCopy());
385 policy_3rdparty.Set("extensions.cccccccccccccccccccccccccccccccc",
386 new base::StringValue("invalid-value"));
387 test_harness_->Install3rdPartyPolicy(&policy_3rdparty);
388
389 provider_->RefreshPolicies();
390 loop_.RunUntilIdle();
391
392 PolicyMap expected_policy;
393 expected_policy.Set(test_keys::kKeyDictionary,
394 test_harness_->policy_level(),
395 test_harness_->policy_scope(),
396 policy_dict.DeepCopy(),
397 NULL);
398 PolicyBundle expected_bundle;
399 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
400 .CopyFrom(expected_policy);
401 expected_policy.Clear();
402 expected_policy.LoadFrom(&policy_dict,
403 test_harness_->policy_level(),
404 test_harness_->policy_scope());
405 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
406 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
407 .CopyFrom(expected_policy);
408 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
409 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
410 .CopyFrom(expected_policy);
411 EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
412 }
413
414 } // namespace policy
415