Chromium Code Reviews| 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 "chrome/browser/policy/cloud_policy_cache_base.h" | |
| 9 #include "chrome/browser/policy/cloud_policy_provider_impl.h" | |
| 10 #include "chrome/browser/policy/configuration_policy_pref_store.h" | |
| 11 #include "chrome/browser/policy/mock_configuration_policy_store.h" | |
| 12 #include "testing/gmock/include/gmock/gmock.h" | |
| 13 | |
| 14 using testing::AnyNumber; | |
| 15 using testing::_; | |
| 16 | |
| 17 namespace policy { | |
| 18 | |
| 19 class MockCloudPolicyCache : public CloudPolicyCacheBase { | |
| 20 public: | |
| 21 MockCloudPolicyCache() {} | |
| 22 virtual ~MockCloudPolicyCache() {} | |
| 23 | |
| 24 // CloudPolicyCacheBase Implementation. | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
lower-case: implementation
gfeher
2011/06/22 19:18:34
Done.
| |
| 25 void Load() {} | |
| 26 void SetPolicy(const em::PolicyFetchResponse& policy) {} | |
| 27 bool DecodePolicyData(const em::PolicyData& policy_data, | |
| 28 PolicyMap* mandatory, | |
| 29 PolicyMap* recommended) { | |
| 30 return true; | |
| 31 } | |
| 32 | |
| 33 // Non-const accessors for underlying PolicyMaps. | |
| 34 PolicyMap* raw_mandatory_policy() { | |
| 35 return &mandatory_policy_; | |
| 36 } | |
| 37 | |
| 38 PolicyMap* raw_recommended_policy() { | |
| 39 return &recommended_policy_; | |
| 40 } | |
| 41 | |
| 42 void SetUnmanaged() { | |
| 43 is_unmanaged_ = true; | |
| 44 } | |
| 45 | |
| 46 void set_initialized(bool initialized) { | |
| 47 initialization_complete_ = initialized; | |
| 48 } | |
| 49 | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
private:
gfeher
2011/06/22 19:18:34
Done.
| |
| 50 DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyCache); | |
| 51 }; | |
| 52 | |
| 53 class CloudPolicyProviderTest : public testing::Test { | |
| 54 protected: | |
| 55 void CreateCloudPolicyProvider( | |
| 56 const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, | |
| 57 CloudPolicyCacheBase::PolicyLevel level) { | |
| 58 cloud_policy_provider_.reset( | |
| 59 new CloudPolicyProviderImpl(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_.get(); | |
| 93 } | |
| 94 | |
| 95 ConfigurationPolicyType simple_list_policy_type(int id) { | |
| 96 DCHECK(id < simple_list_length_); | |
| 97 return simple_list_->begin[id].policy_type; | |
| 98 } | |
| 99 | |
| 100 int simple_list_length() { | |
| 101 return simple_list_length_; | |
| 102 } | |
| 103 | |
| 104 int proxy_policy_count() { | |
| 105 return CloudPolicyProviderImpl::proxy_policy_count(); | |
| 106 } | |
| 107 | |
| 108 bool is_proxy_policy(ConfigurationPolicyType policy) { | |
| 109 return CloudPolicyProviderImpl::is_proxy_policy(policy); | |
| 110 } | |
| 111 | |
| 112 ConfigurationPolicyType get_proxy_policy(int i) { | |
| 113 DCHECK(i < proxy_policy_count()); | |
| 114 return CloudPolicyProviderImpl::proxy_policies[i]; | |
| 115 } | |
| 116 | |
| 117 virtual void SetUp() { | |
| 118 // Extract all non-proxy policies from the default chrome policy definition | |
| 119 // list but set all the types to integer. The names of policies are not | |
| 120 // modified, and they are not used later in these tests. | |
| 121 const ConfigurationPolicyProvider::PolicyDefinitionList* real_list = | |
| 122 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); | |
| 123 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; | |
| 124 | |
| 125 // Count the number of non-proxy policies. | |
| 126 simple_list_length_ = 0; | |
| 127 for (current = real_list->begin; current != real_list->end; ++current) { | |
| 128 if (!CloudPolicyProviderImpl::is_proxy_policy(current->policy_type)) { | |
| 129 ++simple_list_length_; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 int counter = 0; | |
| 134 simple_list_.reset(new ConfigurationPolicyProvider::PolicyDefinitionList); | |
| 135 entries_.reset( | |
| 136 new ConfigurationPolicyProvider::PolicyDefinitionList::Entry[ | |
| 137 simple_list_length_]); | |
| 138 for (current = real_list->begin; current != real_list->end; ++current) { | |
| 139 if (CloudPolicyProviderImpl::is_proxy_policy(current->policy_type)) | |
| 140 continue; | |
| 141 | |
| 142 entries_[counter].policy_type = current->policy_type; | |
| 143 entries_[counter].value_type = Value::TYPE_INTEGER; | |
| 144 entries_[counter].name = current->name; | |
| 145 | |
| 146 ++counter; | |
| 147 } | |
| 148 | |
| 149 simple_list_->begin = entries_.get(); | |
| 150 simple_list_->end = entries_.get() + simple_list_length_; | |
| 151 } | |
| 152 | |
| 153 virtual void TearDown() { | |
| 154 simple_list_.reset(); | |
| 155 entries_.reset(); | |
| 156 } | |
| 157 | |
| 158 // Verify the test scenario of MultipleCaches | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
period.
gfeher
2011/06/22 19:18:34
Done.
| |
| 159 void VerifyMultipleCaches(MockCloudPolicyCache caches[], | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
I don't like this verification code. It's hard to
gfeher
2011/06/22 19:18:34
Done.
| |
| 160 CloudPolicyCacheBase::PolicyLevel level) { | |
| 161 CreateCloudPolicyProvider(simple_list(), level); | |
| 162 MockConfigurationPolicyStore store; | |
| 163 for (int i = 0; i < simple_list_length(); ++i) | |
| 164 AppendCache(&caches[i]); | |
| 165 | |
| 166 EXPECT_CALL(store, Apply(_, _)).Times(AnyNumber()); | |
| 167 Provide(&store); | |
| 168 | |
| 169 const int n = simple_list_length(); | |
| 170 // The final compilation should have exactly two policies per active cache | |
| 171 // set. | |
| 172 for (int i = 0; i < n; ++i) { | |
| 173 const Value* value = store.Get(simple_list_policy_type(i)); | |
| 174 if (i == n - 1 && !caches[i].initialization_complete()) { | |
| 175 // If the last provider is not initialized, then the last policy | |
| 176 // is not provided by anyone. | |
| 177 EXPECT_EQ(NULL, value); | |
| 178 break; | |
| 179 } | |
| 180 ASSERT_TRUE(value != NULL); | |
| 181 int policy_value; | |
| 182 EXPECT_TRUE(value->GetAsInteger(&policy_value)); | |
| 183 int originating_cache = policy_value / n; | |
| 184 int policy_id = policy_value % n; | |
| 185 EXPECT_EQ(i, policy_id) << "Policy identifier mismatch"; | |
| 186 if (caches[i].initialization_complete()) { | |
| 187 // Initialized caches will have their corresponding policy set. | |
| 188 EXPECT_EQ(i, originating_cache) << "Providing cache mismatch."; | |
| 189 } else { | |
| 190 // For non-initialized providers the corresponding value will be set by | |
| 191 // the next provider. (The last provider is handled elsewhere.) | |
| 192 EXPECT_EQ(i + 1, originating_cache) << "Providing cache mismatch."; | |
| 193 } | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 private: | |
| 198 scoped_ptr<CloudPolicyProviderImpl> cloud_policy_provider_; | |
| 199 | |
| 200 // A list of policies to be used in tests: it has some simplifications to | |
| 201 // make testing more easy: it doesn't have proxy policies and all the | |
| 202 // policies have the type of integer. | |
| 203 scoped_ptr<ConfigurationPolicyProvider::PolicyDefinitionList> simple_list_; | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
Why is this so complicated? Can't we just declare
gfeher
2011/06/22 19:18:34
We can go even deeper...
| |
| 204 int simple_list_length_; | |
| 205 | |
| 206 // The following members own the internal parts of simple_list_, therefore | |
| 207 // they may only be freed after simple_list_ is freed. | |
| 208 scoped_array<ConfigurationPolicyProvider::PolicyDefinitionList::Entry> | |
| 209 entries_; | |
| 210 }; | |
| 211 | |
| 212 // Proxy setting distributed over multiple caches. | |
| 213 TEST_F(CloudPolicyProviderTest, | |
| 214 ProxySettingDistributedOverMultipleCaches) { | |
| 215 const int proxy_related_policies = proxy_policy_count(); | |
| 216 | |
| 217 // There are |proxy_related_policies|+1 caches and they are mixed together by | |
| 218 // one instance of CloudPolicyProvider. The first cache has some policies but | |
| 219 // no proxy-related ones. The following caches have each one proxy-policy set. | |
| 220 const int n = proxy_related_policies + 1; | |
| 221 | |
| 222 // Make sure that our assumptions about the existing proxy-related policies | |
| 223 // are still correct. | |
| 224 DCHECK(proxy_related_policies == 5); | |
| 225 | |
| 226 scoped_array<MockCloudPolicyCache> caches(new MockCloudPolicyCache[n]); | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
Just put 5 instead of n and delete all the cruft a
gfeher
2011/06/22 19:18:34
Done.
| |
| 227 | |
| 228 const ConfigurationPolicyProvider::PolicyDefinitionList* list = | |
| 229 policy::ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); | |
| 230 const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; | |
| 231 | |
| 232 // Prepare |cache[0]| to serve some non-proxy policies. | |
| 233 caches[0].set_initialized(true); | |
| 234 caches[0].raw_mandatory_policy()->Set(kPolicyShowHomeButton, | |
| 235 Value::CreateBooleanValue(true)); | |
| 236 caches[0].raw_mandatory_policy()->Set(kPolicyIncognitoEnabled, | |
| 237 Value::CreateBooleanValue(true)); | |
| 238 caches[0].raw_mandatory_policy()->Set(kPolicyTranslateEnabled, | |
| 239 Value::CreateBooleanValue(true)); | |
| 240 | |
| 241 // Prepare the other caches to serve one proxy-policy each. | |
| 242 caches[1].set_initialized(true); | |
| 243 caches[1].raw_mandatory_policy()->Set(kPolicyProxyMode, | |
| 244 Value::CreateStringValue("cache 1")); | |
| 245 caches[2].set_initialized(true); | |
| 246 caches[2].raw_mandatory_policy()->Set(kPolicyProxyServerMode, | |
| 247 Value::CreateIntegerValue(2)); | |
| 248 caches[3].set_initialized(true); | |
| 249 caches[3].raw_mandatory_policy()->Set(kPolicyProxyServer, | |
| 250 Value::CreateStringValue("cache 3")); | |
| 251 caches[4].set_initialized(true); | |
| 252 caches[4].raw_mandatory_policy()->Set(kPolicyProxyPacUrl, | |
| 253 Value::CreateStringValue("cache 4")); | |
| 254 caches[5].set_initialized(true); | |
| 255 caches[5].raw_mandatory_policy()->Set(kPolicyProxyMode, | |
| 256 Value::CreateStringValue("cache 5")); | |
| 257 | |
| 258 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY); | |
| 259 | |
| 260 // Prepend from the end. | |
| 261 for (int i = 0; i < n; ++i) | |
| 262 PrependCache(&caches[n-i-1]); | |
| 263 | |
| 264 MockConfigurationPolicyStore store; | |
| 265 EXPECT_CALL(store, Apply(_, _)).Times(AnyNumber()); | |
| 266 Provide(&store); | |
| 267 | |
| 268 // The final compilation should have some policies set to true. From the proxy | |
| 269 // related policies only |kPolicyProxyMode| should be set. | |
| 270 for (current = list->begin; current != list->end; ++current) { | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
let's just write down what exact expectation we ha
gfeher
2011/06/22 19:18:34
Done.
| |
| 271 const Value* value = store.Get(current->policy_type); | |
| 272 if (current->policy_type == kPolicyProxyMode) { | |
| 273 EXPECT_TRUE(value); | |
| 274 std::string string_value; | |
| 275 bool result = value->GetAsString(&string_value); | |
| 276 EXPECT_TRUE(result); | |
| 277 EXPECT_EQ(string_value, "cache 1"); | |
| 278 } else if (is_proxy_policy(current->policy_type)) { | |
| 279 EXPECT_FALSE(value); | |
| 280 } else if (current->policy_type == kPolicyShowHomeButton || | |
| 281 current->policy_type == kPolicyIncognitoEnabled || | |
| 282 current->policy_type == kPolicyTranslateEnabled) { | |
| 283 EXPECT_TRUE(value); | |
| 284 bool boolean_value = false; | |
| 285 EXPECT_TRUE(value->GetAsBoolean(&boolean_value)); | |
| 286 EXPECT_TRUE(boolean_value); | |
| 287 } else { | |
| 288 EXPECT_FALSE(value); | |
| 289 } | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 // Having many different caches adding them to the end incrementally. | |
| 294 TEST_F(CloudPolicyProviderTest, MultipleCaches) { | |
| 295 const int n = simple_list_length(); | |
| 296 // We set up as many caches as non-proxy policies (n). We configure them | |
| 297 // according to the following pattern: | |
| 298 // The i-th cache will serve i policies and be at position i in the list | |
| 299 // of CloudPolicyProvider. | |
| 300 // The i-th cache will be set to initialized iff i % 2 == 1 | |
| 301 // Thus in the end there should be exactly two policies applied per | |
| 302 // initialized cache. | |
| 303 // The j-th policy of the i-th cache will be set to i * n + j, thus | |
| 304 // given a policy value of x, x / n gives us the cache that provided it and | |
| 305 // x % n should give its own identifier. | |
| 306 // Prepare |cache[i]| to serve the first i policies from |list|. | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
Again, I find this too complicated. Why not just c
gfeher
2011/06/22 19:18:34
Done.
| |
| 307 scoped_array<MockCloudPolicyCache> caches(new MockCloudPolicyCache[n]); | |
| 308 for (int cache_id = 0; cache_id < n; ++cache_id) { | |
| 309 for (int policy_id = 0; policy_id <= cache_id; ++policy_id) { | |
| 310 // Set a unique value. | |
| 311 caches[cache_id].raw_recommended_policy()->Set( | |
| 312 simple_list_policy_type(policy_id), | |
| 313 Value::CreateIntegerValue(cache_id * n + policy_id)); | |
| 314 caches[cache_id].raw_mandatory_policy()->Set( | |
| 315 simple_list_policy_type(policy_id), | |
| 316 Value::CreateIntegerValue(cache_id * n + policy_id)); | |
| 317 | |
| 318 // Odd numbered caches are initialized and evens are not. | |
| 319 caches[cache_id].set_initialized(cache_id % 2); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 // Verify that the provider provides policies according to the expected | |
| 324 // pattern. | |
| 325 VerifyMultipleCaches(caches.get(), | |
| 326 CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); | |
| 327 VerifyMultipleCaches(caches.get(), | |
| 328 CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY); | |
| 329 } | |
| 330 | |
| 331 // Combining two PolicyMaps. | |
| 332 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsSame) { | |
| 333 PolicyMap A, B, C; | |
| 334 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); | |
| 335 for (int i = 0; i < simple_list_length(); ++i) { | |
| 336 A.Set(simple_list_policy_type(i), Value::CreateIntegerValue(i)); | |
| 337 B.Set(simple_list_policy_type(i), 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) { | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
What additional coverage does this test give over
gfeher
2011/06/22 19:18:34
If this doesn't fail but MultipleCaches does, then
| |
| 351 PolicyMap A, B, C; | |
| 352 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); | |
| 353 | |
| 354 for (int i = 0; i < simple_list_length(); ++i) { | |
| 355 B.Set(simple_list_policy_type(i), Value::CreateIntegerValue(-i)); | |
| 356 if (i % 2 == 0) | |
| 357 A.Set(simple_list_policy_type(i), Value::CreateIntegerValue(i)); | |
| 358 } | |
| 359 | |
| 360 CombineTwoPolicyMaps(A, B, &C); | |
| 361 | |
| 362 for (int i = 0; i < simple_list_length(); ++i) { | |
| 363 if (const Value* value = C.Get(simple_list_policy_type(i))) { | |
| 364 int int_value; | |
| 365 EXPECT_TRUE(value->GetAsInteger(&int_value)); | |
| 366 if (i % 2 == 1) { | |
| 367 EXPECT_EQ(int_value, -1 * i); | |
| 368 } else { | |
| 369 EXPECT_EQ(int_value, i); | |
| 370 } | |
| 371 } | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsProxies) { | |
| 376 const int n = proxy_policy_count(); | |
| 377 const int a_value = 1; | |
| 378 const int b_value = -1; | |
| 379 PolicyMap A, B, C; | |
| 380 CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); | |
| 381 | |
| 382 A.Set(get_proxy_policy(0), Value::CreateIntegerValue(a_value)); | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
Why not just use a static constant here?
gfeher
2011/06/22 19:18:34
Done.
| |
| 383 for (int i = 1; i < n; ++i) | |
| 384 B.Set(get_proxy_policy(i), Value::CreateIntegerValue(b_value)); | |
|
Mattias Nissler (ping if slow)
2011/06/21 20:09:56
and here, and unroll the loop?
gfeher
2011/06/22 19:18:34
Done.
| |
| 385 | |
| 386 CombineTwoPolicyMaps(A, B, &C); | |
| 387 | |
| 388 EXPECT_TRUE(A.Equals(C)); | |
| 389 EXPECT_FALSE(B.Equals(C)); | |
| 390 } | |
| 391 | |
| 392 } // namespace policy | |
| OLD | NEW |