Chromium Code Reviews| Index: chrome/browser/policy/cloud_policy_provider_unittest.cc |
| diff --git a/chrome/browser/policy/cloud_policy_provider_unittest.cc b/chrome/browser/policy/cloud_policy_provider_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f3ca5b41c5268ed0fb52152629dcb331e0bed8f3 |
| --- /dev/null |
| +++ b/chrome/browser/policy/cloud_policy_provider_unittest.cc |
| @@ -0,0 +1,377 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/policy/cloud_policy_provider.h" |
| + |
| +#include "base/values.h" |
| +#include "chrome/browser/policy/cloud_policy_cache_base.h" |
| +#include "chrome/browser/policy/cloud_policy_provider.h" |
| +#include "chrome/browser/policy/configuration_policy_pref_store.h" |
| +#include "chrome/browser/policy/mock_configuration_policy_store.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| + |
| +namespace policy { |
| + |
| +namespace { |
| + |
| +ConfigurationPolicyType proxy_policies[]= { kPolicyProxyMode, |
| + kPolicyProxyServerMode, |
| + kPolicyProxyServer, |
| + kPolicyProxyPacUrl, |
| + kPolicyProxyBypassList }; |
| + |
| +bool is_proxy_policy(ConfigurationPolicyType policy) { |
| + const unsigned int n = arraysize(proxy_policies); |
| + bool is_proxy = false; |
| + for (unsigned int i = 0; i < n; ++i) |
| + is_proxy = is_proxy || proxy_policies[i]==policy; |
|
Joao da Silva
2011/06/03 12:23:51
Why not just "return true" here, and "return false
sfeuz
2011/06/03 16:19:29
Done.
|
| + return is_proxy; |
| +} |
| + |
| +} // namespace |
| + |
| +class MockCloudPolicyCacheBase : public CloudPolicyCacheBase { |
| + public: |
| + MockCloudPolicyCacheBase() {} |
| + virtual ~MockCloudPolicyCacheBase() {} |
| + |
| + // CloudPolicyCacheBase Implementation. |
| + void Load(){} |
| + void SetPolicy(const em::PolicyFetchResponse& policy) {} |
| + bool DecodePolicyData(const em::PolicyData& policy_data, |
| + PolicyMap* mandatory, |
| + PolicyMap* recommended) { |
| + return true; |
| + } |
| + |
| + // Non-const accessors for underlying PolicyMaps. |
| + PolicyMap* raw_mandatory_policy() { |
| + return &mandatory_policy_; |
| + } |
| + |
| + PolicyMap* raw_recommended_policy() { |
| + return &recommended_policy_; |
| + } |
| + |
| + void SetUnmanaged() { |
| + is_unmanaged_ = true; |
| + } |
| + |
| + void set_initialized() { |
| + initialization_complete_ = true; |
| + } |
| + |
| + void set_uninitialized() { |
| + initialization_complete_ = false; |
| + } |
| +}; |
| + |
| +class CloudPolicyProviderTest : public testing::Test { |
| + public: |
| + void CreateCloudPolicyProvider( |
| + const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, |
| + CloudPolicyCacheBase::PolicyLevel level) { |
| + cloud_policy_provider_.reset(new CloudPolicyProvider(policy_list, level)); |
| + } |
| + |
| + void CreateCloudPolicyProvider( |
| + CloudPolicyCacheBase::PolicyLevel level) { |
| + CreateCloudPolicyProvider( |
| + policy::ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), |
| + level); |
| + } |
| + |
| + void Provide(ConfigurationPolicyStoreInterface* store) { |
| + DCHECK(cloud_policy_provider_.get()); |
| + cloud_policy_provider_.get()->Provide(store); |
|
Joao da Silva
2011/06/03 12:23:51
The .get() isn't required, just cloud_policy_provi
sfeuz
2011/06/03 16:19:29
Done.
|
| + } |
| + |
| + void AppendCache(CloudPolicyCacheBase* cache) { |
| + DCHECK(cloud_policy_provider_.get()); |
| + cloud_policy_provider_.get()->AppendCache(cache); |
|
Joao da Silva
2011/06/03 12:23:51
Same.
sfeuz
2011/06/03 16:19:29
Done.
|
| + } |
| + |
| + void PrependCache(CloudPolicyCacheBase* cache) { |
| + DCHECK(cloud_policy_provider_.get()); |
| + cloud_policy_provider_.get()->PrependCache(cache); |
|
Joao da Silva
2011/06/03 12:23:51
Same.
sfeuz
2011/06/03 16:19:29
Done.
|
| + } |
| + |
| + void CombineTwoPolicyMaps(const PolicyMap& base, |
| + const PolicyMap& overlay, |
| + PolicyMap* out_map) { |
| + DCHECK(cloud_policy_provider_.get()); |
| + cloud_policy_provider_.get()->CombineTwoPolicyMaps(base, overlay, out_map); |
|
Joao da Silva
2011/06/03 12:23:51
Same.
sfeuz
2011/06/03 16:19:29
Done.
|
| + } |
| + |
| + private: |
| + scoped_ptr<CloudPolicyProvider> cloud_policy_provider_; |
| +}; |
| + |
| +// Proxy setting distributed over multiple caches. |
| +TEST_F(CloudPolicyProviderTest, |
| + ProxySettingDistributedOverMultipleCaches) { |
| + const unsigned int proxy_related_policies = arraysize(proxy_policies); |
| + |
| + // There are |proxy_related_policies|+1 caches and they are mixed together by |
| + // one instance of CloudPolicyProvider. The first cache has some policies but |
| + // no proxy-related ones. The following caches have each one proxy-policy set. |
| + const unsigned int n = proxy_related_policies + 1; |
| + |
| + // Make sure that our assumptions about the existing proxy-related policies |
| + // are still correct. |
| + DCHECK(proxy_related_policies == 5); |
| + |
| + MockCloudPolicyCacheBase caches[n]; |
| + |
| + const ConfigurationPolicyProvider::PolicyDefinitionList* list = |
| + policy::ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); |
| + const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| + |
| + // Prepare |cache[0]| to serve some non-proxy policies. |
| + caches[0].set_initialized(); |
| + caches[0].raw_mandatory_policy()->Set(kPolicyShowHomeButton, |
| + Value::CreateBooleanValue(true)); |
|
Joao da Silva
2011/06/03 12:23:51
Indent (also on the lines below)
sfeuz
2011/06/03 16:19:29
Done.
|
| + caches[0].raw_mandatory_policy()->Set(kPolicyIncognitoEnabled, |
| + Value::CreateBooleanValue(true)); |
| + caches[0].raw_mandatory_policy()->Set(kPolicyTranslateEnabled, |
| + Value::CreateBooleanValue(true)); |
| + |
| + // Prepare the other caches to serve one proxy-policy each. |
| + caches[1].set_initialized(); |
| + caches[1].raw_mandatory_policy()->Set(kPolicyProxyMode, |
| + Value::CreateStringValue("cache 1")); |
| + caches[2].set_initialized(); |
| + caches[2].raw_mandatory_policy()->Set(kPolicyProxyServerMode, |
| + Value::CreateIntegerValue(2)); |
| + caches[3].set_initialized(); |
| + caches[3].raw_mandatory_policy()->Set(kPolicyProxyServer, |
| + Value::CreateStringValue("cache 3")); |
| + caches[4].set_initialized(); |
| + caches[4].raw_mandatory_policy()->Set(kPolicyProxyPacUrl, |
| + Value::CreateStringValue("cache 4")); |
| + caches[5].set_initialized(); |
| + caches[5].raw_mandatory_policy()->Set(kPolicyProxyMode, |
| + Value::CreateStringValue("cache 5")); |
| + |
| + CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY); |
| + |
| + // Prepend from the end. |
| + for (unsigned int i = 0; i < n; ++i) |
| + PrependCache(&caches[n-i-1]); |
| + |
| + MockConfigurationPolicyStore store; |
| + EXPECT_CALL(store, Apply(testing::_,testing::_)).Times(testing::AnyNumber()); |
| + Provide(&store); |
| + |
| + // The final compilation should have some policies set to true. From the proxy |
| + // related policies only |kPolicyProxyMode| should be set. |
| + for (current = list->begin; current != list->end; ++current) { |
| + const Value* value = store.Get(current->policy_type); |
| + if (current->policy_type == kPolicyProxyMode) { |
| + EXPECT_TRUE(value); |
| + std::string string_value; |
| + bool result = value->GetAsString(&string_value); |
| + EXPECT_TRUE(result); |
| + EXPECT_EQ(string_value, "cache 1"); |
| + } else if (is_proxy_policy(current->policy_type)) { |
| + EXPECT_FALSE(value); |
| + } else if (current->policy_type == kPolicyShowHomeButton || |
| + current->policy_type == kPolicyIncognitoEnabled || |
| + current->policy_type == kPolicyTranslateEnabled) { |
| + EXPECT_TRUE(value); |
| + bool boolean_value = false; |
| + bool result = value->GetAsBoolean(&boolean_value); |
| + DCHECK(result); |
| + EXPECT_TRUE(boolean_value); |
| + } else { |
| + EXPECT_FALSE(value); |
| + } |
| + } |
| +} |
| + |
| +// Having many different caches adding them to the end incrementally. |
| +TEST_F(CloudPolicyProviderTest, MultipleCaches) { |
| + // |n| denotes the number of caches, which are mixed together by one |
| + // instance of CloudPolicyProvider. Every other cache is set to be |
| + // initialized (starting with a non-initialized one). The i-th cache will |
| + // serve i policies and be at position i in the list of CloudPolicyProvider. |
| + // Thus in the end there should be exactly two policies/ applied per |
| + // initialized cache. |
| + const unsigned int n = 101; |
| + const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; |
| + const char* key_template = "Policy %03u"; |
| + |
| + // Numbers bigger than 1000 will mess with the key_template. |
| + DCHECK(n - arraysize(proxy_policies) < 1000); |
| + |
| + // Prepare the PolicyDefinitionList |simple_list| with entries of the form |
| + // {(ConfigurationPolicyType)(7), Value::TYPE_INTEGER, "Policy 007"}. |
| + ConfigurationPolicyProvider::PolicyDefinitionList::Entry entries[n]; |
| + |
| + // Note that |key_template| is exactly one char longer than the resulting |
| + // keys, thus making the arrays correctly sized (including the trailing \0). |
| + const unsigned int key_length = strlen(key_template); |
| + char keys[n][key_length]; |
| + unsigned int counter = 0; |
| + for (unsigned int i = 0; i < n; ++counter) { |
| + |
| + // We do not want to interfere with the proxy related policies since they |
| + // are treated as a special case inside CloudPolicyProvider. |
| + if (is_proxy_policy((ConfigurationPolicyType)counter)) |
| + continue; |
| + |
| + snprintf(keys[i], key_length, key_template, counter); |
| + entries[i].policy_type = (ConfigurationPolicyType)counter; |
| + entries[i].value_type = Value::TYPE_INTEGER; |
| + entries[i].name = (const char*)keys[i]; |
| + ++i; |
| + } |
| + const int max_counter = counter; |
| + ConfigurationPolicyProvider::PolicyDefinitionList simple_list = |
| + {entries, |
| + entries+n}; |
| + |
| + // Prepare |cache[i]| to serve the first i policies form |simple_list|. |
| + MockCloudPolicyCacheBase caches[n]; |
| + for (unsigned int i = 0; i < n; ++i) { |
| + current = simple_list.begin; |
| + for (unsigned int j = 0; j <= i; ++j, ++current) { |
| + // Set a unique value. |
| + caches[i].raw_recommended_policy()->Set( |
| + current->policy_type, |
| + Value::CreateIntegerValue(i*max_counter + |
| + (int)current->policy_type)); |
| + caches[i].raw_mandatory_policy()->Set( |
| + current->policy_type, |
| + Value::CreateIntegerValue(i*max_counter + |
| + (int)current->policy_type)); |
| + if (i&1) |
| + caches[i].set_initialized(); |
| + else |
| + caches[i].set_uninitialized(); |
| + } |
|
Joao da Silva
2011/06/03 12:23:51
Indent.
sfeuz
2011/06/03 16:19:29
Done.
|
| + } |
| + |
| + // Executed twice. Once for recommended and once for mandatory policy level. |
| + for (int l = 0; l < 2; ++l) { |
| + CloudPolicyCacheBase::PolicyLevel level = l ? |
| + CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED: |
| + CloudPolicyCacheBase::POLICY_LEVEL_MANDATORY; |
| + CreateCloudPolicyProvider(&simple_list,level); |
| + MockConfigurationPolicyStore store; |
| + current = simple_list.begin; |
| + for (unsigned int i = 0; i < n; ++i) |
| + AppendCache(&caches[i]); |
| + |
| + EXPECT_CALL(store, Apply(testing::_,testing::_)).Times( |
| + testing::AnyNumber()); |
| + Provide(&store); |
| + |
| + // The final compilation should have exactly two policies per active cache |
| + // set. |
| + current = simple_list.begin; |
| + for (unsigned int i = 0; i < n; ++i, ++current) { |
| + |
| + // Initialized caches will have their corresponding policy set. |
| + if (caches[i].initialization_complete()) { |
| + const Value* value = store.Get(current->policy_type); |
| + EXPECT_TRUE(value); |
| + int expected = i*max_counter + (int)current->policy_type; |
| + int integer_value; |
| + bool result = value->GetAsInteger(&integer_value); |
| + EXPECT_TRUE(result); |
| + EXPECT_EQ(integer_value, expected); |
| + } else { |
| + |
| + // For non-initialized providers the corresponding value will be set by |
| + // the next provider, except if it is the last one. |
| + if (i == n-1) { |
| + EXPECT_FALSE(store.Get(current->policy_type)); |
| + break; |
| + } |
| + |
| + const Value* value = store.Get(current->policy_type); |
| + EXPECT_TRUE(value); |
| + int expected = (i+1)*max_counter + (int)current->policy_type; |
| + int integer_value; |
| + bool result = value->GetAsInteger(&integer_value); |
| + EXPECT_TRUE(result); |
| + EXPECT_EQ(integer_value, expected); |
| + } |
| + } |
| + } |
| +} |
| + |
| + // Combining two PolicyMaps. |
| +TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsSame) { |
| + const int n = 1000; |
| + PolicyMap A, B, C; |
| + CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| + |
| + for (int i=0; i < n; ++i) |
| + if (!is_proxy_policy((ConfigurationPolicyType)i)) |
| + A.Set((ConfigurationPolicyType)i,Value::CreateIntegerValue(i)); |
| + |
| + for (int i=0; i < n; ++i) |
| + if (!is_proxy_policy((ConfigurationPolicyType)i)) |
| + B.Set((ConfigurationPolicyType)i,Value::CreateIntegerValue(-1*i)); |
| + |
| + CombineTwoPolicyMaps(A,B,&C); |
| + EXPECT_TRUE(A.Equals(C)); |
| +} |
| + |
| +TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsEmpty) { |
| + PolicyMap A, B, C; |
| + CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| + CombineTwoPolicyMaps(A,B,&C); |
| + EXPECT_TRUE(C.empty()); |
| +} |
| + |
| +TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsPartial) { |
| + const int n = 1000; |
| + PolicyMap A, B, C; |
| + CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| + |
| + for (int i=0; i < n; ++i) { |
| + if (is_proxy_policy((ConfigurationPolicyType)(2*i)) || |
| + is_proxy_policy((ConfigurationPolicyType)(2*i+1))) { |
| + continue; |
| + } |
| + A.Set((ConfigurationPolicyType)(2*i),Value::CreateIntegerValue(2*i)); |
| + B.Set((ConfigurationPolicyType)(2*i),Value::CreateIntegerValue(-2*i)); |
| + B.Set((ConfigurationPolicyType)(2*i+1),Value::CreateIntegerValue(-2*i-1)); |
| + } |
| + |
| + CombineTwoPolicyMaps(A,B,&C); |
| + |
| + for (int i=0; i < 2*n; ++i) { |
| + if (const Value* value = C.Get((ConfigurationPolicyType)i)) { |
| + int int_value; |
| + EXPECT_TRUE(value->GetAsInteger(&int_value)); |
| + if (i&1) |
| + EXPECT_EQ(int_value, -1*i); |
| + else |
| + EXPECT_EQ(int_value, i); |
| + } |
| + } |
| +} |
| + |
| +TEST_F(CloudPolicyProviderTest, CombineTwoPolicyMapsProxies) { |
| + const int n = arraysize(proxy_policies); |
| + const int a_value = 1; |
| + const int b_value = -1; |
| + PolicyMap A, B, C; |
| + CreateCloudPolicyProvider(CloudPolicyCacheBase::POLICY_LEVEL_RECOMMENDED); |
| + |
| + A.Set(proxy_policies[0], Value::CreateIntegerValue(a_value)); |
| + for (int i=1; i < n; ++i) |
| + B.Set(proxy_policies[i], Value::CreateIntegerValue(b_value)); |
| + |
| + CombineTwoPolicyMaps(A,B,&C); |
| + |
| + EXPECT_TRUE(A.Equals(C)); |
| + EXPECT_FALSE(B.Equals(C)); |
| +} |
| + |
| +} // namespace policy |