OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "chrome/browser/policy/cloud_policy_provider.h" |
| 6 |
| 7 #include "base/values.h" |
| 8 #include "base/string_util.h" |
| 9 #include "chrome/browser/policy/cloud_policy_cache_base.h" |
| 10 #include "chrome/browser/policy/cloud_policy_provider.h" |
| 11 #include "chrome/browser/policy/configuration_policy_pref_store.h" |
| 12 #include "chrome/browser/policy/mock_configuration_policy_store.h" |
| 13 #include "testing/gmock/include/gmock/gmock.h" |
| 14 |
| 15 using testing::AnyNumber; |
| 16 using testing::_; |
| 17 |
| 18 namespace policy { |
| 19 |
| 20 class MockCloudPolicyCacheBase : public CloudPolicyCacheBase { |
| 21 public: |
| 22 MockCloudPolicyCacheBase() {} |
| 23 virtual ~MockCloudPolicyCacheBase() {} |
| 24 |
| 25 // CloudPolicyCacheBase Implementation. |
| 26 void Load(){} |
| 27 void SetPolicy(const em::PolicyFetchResponse& policy) {} |
| 28 bool DecodePolicyData(const em::PolicyData& policy_data, |
| 29 PolicyMap* mandatory, |
| 30 PolicyMap* recommended) { |
| 31 return true; |
| 32 } |
| 33 |
| 34 // Non-const accessors for underlying PolicyMaps. |
| 35 PolicyMap* raw_mandatory_policy() { |
| 36 return &mandatory_policy_; |
| 37 } |
| 38 |
| 39 PolicyMap* raw_recommended_policy() { |
| 40 return &recommended_policy_; |
| 41 } |
| 42 |
| 43 void SetUnmanaged() { |
| 44 is_unmanaged_ = true; |
| 45 } |
| 46 |
| 47 void set_initialized(bool initialized) { |
| 48 initialization_complete_ = initialized; |
| 49 } |
| 50 |
| 51 DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyCacheBase); |
| 52 }; |
| 53 |
| 54 class CloudPolicyProviderTest : public testing::Test { |
| 55 public: |
| 56 void CreateCloudPolicyProvider( |
| 57 const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, |
| 58 CloudPolicyCacheBase::PolicyLevel level) { |
| 59 cloud_policy_provider_.reset(new CloudPolicyProvider(policy_list, level)); |
| 60 } |
| 61 |
| 62 void CreateCloudPolicyProvider( |
| 63 CloudPolicyCacheBase::PolicyLevel level) { |
| 64 CreateCloudPolicyProvider( |
| 65 policy::ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), |
| 66 level); |
| 67 } |
| 68 |
| 69 void Provide(ConfigurationPolicyStoreInterface* store) { |
| 70 DCHECK(cloud_policy_provider_.get()); |
| 71 cloud_policy_provider_->Provide(store); |
| 72 } |
| 73 |
| 74 void AppendCache(CloudPolicyCacheBase* cache) { |
| 75 DCHECK(cloud_policy_provider_.get()); |
| 76 cloud_policy_provider_->AppendCache(cache); |
| 77 } |
| 78 |
| 79 void PrependCache(CloudPolicyCacheBase* cache) { |
| 80 DCHECK(cloud_policy_provider_.get()); |
| 81 cloud_policy_provider_->PrependCache(cache); |
| 82 } |
| 83 |
| 84 void CombineTwoPolicyMaps(const PolicyMap& base, |
| 85 const PolicyMap& overlay, |
| 86 PolicyMap* out_map) { |
| 87 DCHECK(cloud_policy_provider_.get()); |
| 88 cloud_policy_provider_->CombineTwoPolicyMaps(base, overlay, out_map); |
| 89 } |
| 90 |
| 91 ConfigurationPolicyProvider::PolicyDefinitionList* simple_list() { |
| 92 return &simple_list_; |
| 93 } |
| 94 |
| 95 unsigned int simple_list_length() { |
| 96 return simple_list_length_; |
| 97 } |
| 98 |
| 99 unsigned int proxy_policy_count() { |
| 100 return CloudPolicyProvider::proxy_policy_count(); |
| 101 } |
| 102 |
| 103 bool is_proxy_policy(ConfigurationPolicyType policy) { |
| 104 return CloudPolicyProvider::is_proxy_policy(policy); |
| 105 } |
| 106 |
| 107 ConfigurationPolicyType get_proxy_policy(unsigned int i) { |
| 108 DCHECK(i<proxy_policy_count()); |
| 109 return CloudPolicyProvider::proxy_policies[i]; |
| 110 } |
| 111 protected: |
| 112 virtual void SetUp() { |
| 113 // Extract all non-proxy policies from the default chrome policy definition |
| 114 // list but set all the types to integer and set the names to the zero-based |
| 115 // index. |
| 116 // For example the 8-th elements will be of the form: |
| 117 // {ConfigurationPolicyType, Value::TYPE_INTEGER, "007"} |
| 118 const ConfigurationPolicyProvider::PolicyDefinitionList* real_list = |
| 119 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); |
| 120 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| 121 |
| 122 // Counting the number of non-proxy policies. |
| 123 unsigned int n = 0; |
| 124 for (current = real_list->begin; current != real_list->end; ++current) { |
| 125 if (!CloudPolicyProvider::is_proxy_policy(current->policy_type)) { |
| 126 ++n; |
| 127 } |
| 128 } |
| 129 |
| 130 // Numbers bigger than 1000 will mess with the key names. |
| 131 DCHECK(n < 1000); |
| 132 |
| 133 unsigned int counter = 0; |
| 134 entries.reset( |
| 135 new ConfigurationPolicyProvider::PolicyDefinitionList::Entry[n]); |
| 136 for (current = real_list->begin; current != real_list->end; ++current) { |
| 137 if (CloudPolicyProvider::is_proxy_policy(current->policy_type)) |
| 138 continue; |
| 139 |
| 140 // The size of the keys depends on their format. Currently they are of the |
| 141 // form "007" needing 4 characters including the terminal \0. |
| 142 char* key = new char[4]; |
| 143 base::snprintf(key, 4, "%03u", counter); |
| 144 |
| 145 entries[counter].policy_type = current->policy_type; |
| 146 entries[counter].value_type = Value::TYPE_INTEGER; |
| 147 entries[counter].name = key; |
| 148 ++counter; |
| 149 } |
| 150 |
| 151 simple_list_.begin = entries.get(); |
| 152 simple_list_.end = entries.get() + n; |
| 153 } |
| 154 |
| 155 private: |
| 156 scoped_ptr<CloudPolicyProvider> cloud_policy_provider_; |
| 157 ConfigurationPolicyProvider::PolicyDefinitionList simple_list_; |
| 158 scoped_array<ConfigurationPolicyProvider::PolicyDefinitionList::Entry> |
| 159 entries; |
| 160 unsigned int simple_list_length_; |
| 161 }; |
| 162 |
| 163 // Proxy setting distributed over multiple caches. |
| 164 TEST_F(CloudPolicyProviderTest, |
| 165 ProxySettingDistributedOverMultipleCaches) { |
| 166 const unsigned int proxy_related_policies = proxy_policy_count(); |
| 167 |
| 168 // There are |proxy_related_policies|+1 caches and they are mixed together by |
| 169 // one instance of CloudPolicyProvider. The first cache has some policies but |
| 170 // no proxy-related ones. The following caches have each one proxy-policy set. |
| 171 const unsigned int n = proxy_related_policies + 1; |
| 172 |
| 173 // Make sure that our assumptions about the existing proxy-related policies |
| 174 // are still correct. |
| 175 DCHECK(proxy_related_policies == 5); |
| 176 |
| 177 MockCloudPolicyCacheBase caches[n]; |
| 178 |
| 179 const ConfigurationPolicyProvider::PolicyDefinitionList* list = |
| 180 policy::ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); |
| 181 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| 182 |
| 183 // Prepare |cache[0]| to serve some non-proxy policies. |
| 184 caches[0].set_initialized(true); |
| 185 caches[0].raw_mandatory_policy()->Set(kPolicyShowHomeButton, |
| 186 Value::CreateBooleanValue(true)); |
| 187 caches[0].raw_mandatory_policy()->Set(kPolicyIncognitoEnabled, |
| 188 Value::CreateBooleanValue(true)); |
| 189 caches[0].raw_mandatory_policy()->Set(kPolicyTranslateEnabled, |
| 190 Value::CreateBooleanValue(true)); |
| 191 |
| 192 // Prepare the other caches to serve one proxy-policy each. |
| 193 caches[1].set_initialized(true); |
| 194 caches[1].raw_mandatory_policy()->Set(kPolicyProxyMode, |
| 195 Value::CreateStringValue("cache 1")); |
| 196 caches[2].set_initialized(true); |
| 197 caches[2].raw_mandatory_policy()->Set(kPolicyProxyServerMode, |
| 198 Value::CreateIntegerValue(2)); |
| 199 caches[3].set_initialized(true); |
| 200 caches[3].raw_mandatory_policy()->Set(kPolicyProxyServer, |
| 201 Value::CreateStringValue("cache 3")); |
| 202 caches[4].set_initialized(true); |
| 203 caches[4].raw_mandatory_policy()->Set(kPolicyProxyPacUrl, |
| 204 Value::CreateStringValue("cache 4")); |
| 205 caches[5].set_initialized(true); |
| 206 caches[5].raw_mandatory_policy()->Set(kPolicyProxyMode, |
| 207 Value::CreateStringValue("cache 5")); |
| 208 |
| 209 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY); |
| 210 |
| 211 // Prepend from the end. |
| 212 for (unsigned int i = 0; i < n; ++i) |
| 213 PrependCache(&caches[n-i-1]); |
| 214 |
| 215 MockConfigurationPolicyStore store; |
| 216 EXPECT_CALL(store, Apply(_, _)).Times(AnyNumber()); |
| 217 Provide(&store); |
| 218 |
| 219 // The final compilation should have some policies set to true. From the proxy |
| 220 // related policies only |kPolicyProxyMode| should be set. |
| 221 for (current = list->begin; current != list->end; ++current) { |
| 222 const Value* value = store.Get(current->policy_type); |
| 223 if (current->policy_type == kPolicyProxyMode) { |
| 224 EXPECT_TRUE(value); |
| 225 std::string string_value; |
| 226 bool result = value->GetAsString(&string_value); |
| 227 EXPECT_TRUE(result); |
| 228 EXPECT_EQ(string_value, "cache 1"); |
| 229 } else if (is_proxy_policy(current->policy_type)) { |
| 230 EXPECT_FALSE(value); |
| 231 } else if (current->policy_type == kPolicyShowHomeButton || |
| 232 current->policy_type == kPolicyIncognitoEnabled || |
| 233 current->policy_type == kPolicyTranslateEnabled) { |
| 234 EXPECT_TRUE(value); |
| 235 bool boolean_value = false; |
| 236 bool result = value->GetAsBoolean(&boolean_value); |
| 237 EXPECT_TRUE(result); |
| 238 EXPECT_TRUE(boolean_value); |
| 239 } else { |
| 240 EXPECT_FALSE(value); |
| 241 } |
| 242 } |
| 243 } |
| 244 |
| 245 // Having many different caches adding them to the end incrementally. |
| 246 TEST_F(CloudPolicyProviderTest, MultipleCaches) { |
| 247 // We have as many caches as non-proxy policies. Every other cache is set to |
| 248 // be initialized (starting with a non-initialized one). The i-th cache will |
| 249 // serve i policies and be at position i in the list of CloudPolicyProvider. |
| 250 // Thus in the end there should be exactly two policies applied per |
| 251 // initialized cache. |
| 252 |
| 253 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| 254 const ConfigurationPolicyProvider::PolicyDefinitionList* list = simple_list(); |
| 255 |
| 256 const unsigned int n = simple_list_length(); |
| 257 |
| 258 // Prepare |cache[i]| to serve the first i policies from |list|. |
| 259 MockCloudPolicyCacheBase caches[n]; |
| 260 for (unsigned int i = 0; i < n; ++i) { |
| 261 current = list->begin; |
| 262 for (unsigned int j = 0; j <= i; ++j) { |
| 263 // Set a unique value. |
| 264 caches[i].raw_recommended_policy()->Set( |
| 265 current->policy_type, |
| 266 Value::CreateIntegerValue(i * n + j)); |
| 267 caches[i].raw_mandatory_policy()->Set( |
| 268 current->policy_type, |
| 269 Value::CreateIntegerValue(i * n + j)); |
| 270 |
| 271 // Odd numbers are initialized and even are not. |
| 272 caches[i].set_initialized(i & 1); |
| 273 } |
| 274 } |
| 275 |
| 276 // Executed twice. Once for recommended and once for mandatory policy level. |
| 277 for (int l = 0; l < 2; ++l) { |
| 278 CloudPolicyCacheBase::PolicyLevel level = l ? |
| 279 CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED : |
| 280 CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY; |
| 281 CreateCloudPolicyProvider(list,level); |
| 282 MockConfigurationPolicyStore store; |
| 283 current = list->begin; |
| 284 for (unsigned int i = 0; i < n; ++i) |
| 285 AppendCache(&caches[i]); |
| 286 |
| 287 EXPECT_CALL(store, Apply(_, _)).Times(AnyNumber()); |
| 288 Provide(&store); |
| 289 |
| 290 // The final compilation should have exactly two policies per active cache |
| 291 // set. |
| 292 current = list->begin; |
| 293 for (unsigned int i = 0; i < n; ++i, ++current) { |
| 294 // Initialized caches will have their corresponding policy set. |
| 295 if (caches[i].initialization_complete()) { |
| 296 const Value* value = store.Get(current->policy_type); |
| 297 EXPECT_TRUE(value); |
| 298 int expected = i * n + i; |
| 299 int integer_value; |
| 300 bool result = value->GetAsInteger(&integer_value); |
| 301 EXPECT_TRUE(result); |
| 302 EXPECT_EQ(integer_value, expected); |
| 303 } else { |
| 304 // For non-initialized providers the corresponding value will be set by |
| 305 // the next provider, except if it is the last one. |
| 306 if (i == n-1) { |
| 307 EXPECT_FALSE(store.Get(current->policy_type)); |
| 308 break; |
| 309 } |
| 310 |
| 311 const Value* value = store.Get(current->policy_type); |
| 312 EXPECT_TRUE(value); |
| 313 int expected = (i + 1) * n + (int) i; |
| 314 int integer_value; |
| 315 bool result = value->GetAsInteger(&integer_value); |
| 316 EXPECT_TRUE(result); |
| 317 EXPECT_EQ(integer_value, expected); |
| 318 } |
| 319 } |
| 320 } |
| 321 } |
| 322 |
| 323 // Combining two PolicyMaps. |
| 324 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsSame) { |
| 325 PolicyMap A, B, C; |
| 326 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| 327 const ConfigurationPolicyProvider::PolicyDefinitionList* list = |
| 328 simple_list(); |
| 329 const int n = (int) simple_list_length(); |
| 330 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| 331 current = list->begin; |
| 332 for (int i=0; i < n; ++i, ++current) |
| 333 A.Set(current->policy_type, Value::CreateIntegerValue(i)); |
| 334 |
| 335 current = list->begin; |
| 336 for (int i=0; i < n; ++i, ++current) |
| 337 B.Set(current->policy_type, Value::CreateIntegerValue(-1 * i)); |
| 338 |
| 339 CombineTwoPolicyMaps(A, B, &C); |
| 340 EXPECT_TRUE(A.Equals(C)); |
| 341 } |
| 342 |
| 343 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsEmpty) { |
| 344 PolicyMap A, B, C; |
| 345 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| 346 CombineTwoPolicyMaps(A, B, &C); |
| 347 EXPECT_TRUE(C.empty()); |
| 348 } |
| 349 |
| 350 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsPartial) { |
| 351 PolicyMap A, B, C; |
| 352 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| 353 const ConfigurationPolicyProvider::PolicyDefinitionList* list = simple_list(); |
| 354 const int n = (int) simple_list_length(); |
| 355 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| 356 |
| 357 current = list->begin; |
| 358 for (int i=0; i < n; ++i, ++current) { |
| 359 B.Set(current->policy_type, Value::CreateIntegerValue(-i)); |
| 360 if (!(i & 1)) |
| 361 A.Set(current->policy_type, Value::CreateIntegerValue(i)); |
| 362 } |
| 363 |
| 364 CombineTwoPolicyMaps(A, B, &C); |
| 365 |
| 366 current = list->begin; |
| 367 for (int i=0; i < n; ++i, ++current) { |
| 368 if (const Value* value = C.Get(current->policy_type)) { |
| 369 int int_value; |
| 370 EXPECT_TRUE(value->GetAsInteger(&int_value)); |
| 371 if (i & 1) |
| 372 EXPECT_EQ(int_value, -1 * i); |
| 373 else |
| 374 EXPECT_EQ(int_value, i); |
| 375 } |
| 376 } |
| 377 } |
| 378 |
| 379 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsProxies) { |
| 380 const int n = proxy_policy_count(); |
| 381 const int a_value = 1; |
| 382 const int b_value = -1; |
| 383 PolicyMap A, B, C; |
| 384 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| 385 |
| 386 A.Set(get_proxy_policy(0), Value::CreateIntegerValue(a_value)); |
| 387 for (int i=1; i < n; ++i) |
| 388 B.Set(get_proxy_policy(i), Value::CreateIntegerValue(b_value)); |
| 389 |
| 390 CombineTwoPolicyMaps(A, B, &C); |
| 391 |
| 392 EXPECT_TRUE(A.Equals(C)); |
| 393 EXPECT_FALSE(B.Equals(C)); |
| 394 } |
| 395 |
| 396 } // namespace policy |
OLD | NEW |