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 124 PolicyTestBase::PolicyTestBase() {} 125 126 PolicyTestBase::~PolicyTestBase() {} 127 128 void PolicyTestBase::SetUp() { 129 const PolicyNamespace ns(POLICY_DOMAIN_CHROME, ""); 130 ASSERT_TRUE(RegisterSchema(ns, kTestChromeSchema)); 131 } 132 133 void PolicyTestBase::TearDown() { 134 loop_.RunUntilIdle(); 135 } 136 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 149 PolicyProviderTestHarness::PolicyProviderTestHarness(PolicyLevel level, 150 PolicyScope scope) 151 : level_(level), scope_(scope) {} 152 153 PolicyProviderTestHarness::~PolicyProviderTestHarness() {} 154 155 PolicyLevel PolicyProviderTestHarness::policy_level() const { 156 return level_; 157 } 158 159 PolicyScope PolicyProviderTestHarness::policy_scope() const { 160 return scope_; 161 } 162 163 void PolicyProviderTestHarness::Install3rdPartyPolicy( 164 const base::DictionaryValue* policies) { 165 FAIL(); 166 } 167 168 ConfigurationPolicyProviderTest::ConfigurationPolicyProviderTest() {} 169 170 ConfigurationPolicyProviderTest::~ConfigurationPolicyProviderTest() {} 171 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 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 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 235 TEST_P(ConfigurationPolicyProviderTest, Empty) { 236 provider_->RefreshPolicies(); 237 loop_.RunUntilIdle(); 238 const PolicyBundle kEmptyBundle; 239 EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle)); 240 } 241 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 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 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 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 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 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:: 351 Configuration3rdPartyPolicyProviderTest() {} 352 353 Configuration3rdPartyPolicyProviderTest:: 354 ~Configuration3rdPartyPolicyProviderTest() {} 355 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