diff options
author | dconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-22 11:48:57 +0000 |
---|---|---|
committer | dconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-22 11:48:57 +0000 |
commit | 3af8f808950710f6a054646f749e51526624eab5 (patch) | |
tree | 40a3295ecc045b9176bdc5ed98ccf51cd9c6dcdb /components | |
parent | 449c07370159f5e0899eb857de459656b3dfb3f2 (diff) | |
download | chromium_src-3af8f808950710f6a054646f749e51526624eab5.zip chromium_src-3af8f808950710f6a054646f749e51526624eab5.tar.gz chromium_src-3af8f808950710f6a054646f749e51526624eab5.tar.bz2 |
Move PolicyBundle into components/policy/.
This facilitates the refactoring of chrome/browser/policy into a layered
component.
Depends on https://codereview.chromium.org/78763002/
BUG=271392
Review URL: https://codereview.chromium.org/78823004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236747 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r-- | components/components_tests.gyp | 1 | ||||
-rw-r--r-- | components/policy.gypi | 2 | ||||
-rw-r--r-- | components/policy/core/common/external_data_manager.h | 3 | ||||
-rw-r--r-- | components/policy/core/common/policy_bundle.cc | 110 | ||||
-rw-r--r-- | components/policy/core/common/policy_bundle.h | 73 | ||||
-rw-r--r-- | components/policy/core/common/policy_bundle_unittest.cc | 260 |
6 files changed, 448 insertions, 1 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index e8c9b89..96d1cd3 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -171,6 +171,7 @@ }], ['configuration_policy==1', { 'sources': [ + 'policy/core/common/policy_bundle_unittest.cc', 'policy/core/common/policy_map_unittest.cc', 'policy/core/common/schema_unittest.cc', ], diff --git a/components/policy.gypi b/components/policy.gypi index 2ac51d8..9c2c34c 100644 --- a/components/policy.gypi +++ b/components/policy.gypi @@ -20,6 +20,8 @@ 'conditions': [ ['configuration_policy==1', { 'sources': [ + 'policy/core/common/policy_bundle.cc', + 'policy/core/common/policy_bundle.h', 'policy/core/common/external_data_fetcher.cc', 'policy/core/common/external_data_fetcher.h', 'policy/core/common/external_data_manager.h', diff --git a/components/policy/core/common/external_data_manager.h b/components/policy/core/common/external_data_manager.h index fa69953..406cf59 100644 --- a/components/policy/core/common/external_data_manager.h +++ b/components/policy/core/common/external_data_manager.h @@ -8,6 +8,7 @@ #include <string> #include "components/policy/core/common/external_data_fetcher.h" +#include "components/policy/policy_export.h" namespace policy { @@ -16,7 +17,7 @@ namespace policy { // An implementation of this abstract interface should be provided for each // policy source (cloud policy, platform policy) that supports external data // references. -class ExternalDataManager { +class POLICY_EXPORT ExternalDataManager { public: // Retrieves the external data referenced by |policy| and invokes |callback| // with the result. If |policy| does not reference any external data, the diff --git a/components/policy/core/common/policy_bundle.cc b/components/policy/core/common/policy_bundle.cc new file mode 100644 index 0000000..96d7e82 --- /dev/null +++ b/components/policy/core/common/policy_bundle.cc @@ -0,0 +1,110 @@ +// Copyright 2013 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 "components/policy/core/common/policy_bundle.h" + +#include "base/logging.h" +#include "base/stl_util.h" + +namespace policy { + +PolicyBundle::PolicyBundle() {} + +PolicyBundle::~PolicyBundle() { + Clear(); +} + +PolicyMap& PolicyBundle::Get(const PolicyNamespace& ns) { + DCHECK(ns.domain != POLICY_DOMAIN_CHROME || ns.component_id.empty()); + PolicyMap*& policy = policy_bundle_[ns]; + if (!policy) + policy = new PolicyMap(); + return *policy; +} + +const PolicyMap& PolicyBundle::Get(const PolicyNamespace& ns) const { + DCHECK(ns.domain != POLICY_DOMAIN_CHROME || ns.component_id.empty()); + const_iterator it = policy_bundle_.find(ns); + return it == end() ? kEmpty_ : *it->second; +} + +void PolicyBundle::Swap(PolicyBundle* other) { + policy_bundle_.swap(other->policy_bundle_); +} + +void PolicyBundle::CopyFrom(const PolicyBundle& other) { + Clear(); + for (PolicyBundle::const_iterator it = other.begin(); + it != other.end(); ++it) { + policy_bundle_[it->first] = it->second->DeepCopy().release(); + } +} + +void PolicyBundle::MergeFrom(const PolicyBundle& other) { + // Iterate over both |this| and |other| in order; skip what's extra in |this|, + // add what's missing, and merge the namespaces in common. + MapType::iterator it_this = policy_bundle_.begin(); + MapType::iterator end_this = policy_bundle_.end(); + const_iterator it_other = other.begin(); + const_iterator end_other = other.end(); + + while (it_this != end_this && it_other != end_other) { + if (it_this->first == it_other->first) { + // Same namespace: merge existing PolicyMaps. + it_this->second->MergeFrom(*it_other->second); + ++it_this; + ++it_other; + } else if (it_this->first < it_other->first) { + // |this| has a PolicyMap that |other| doesn't; skip it. + ++it_this; + } else if (it_other->first < it_this->first) { + // |other| has a PolicyMap that |this| doesn't; copy it. + PolicyMap*& policy = policy_bundle_[it_other->first]; + DCHECK(!policy); + policy = it_other->second->DeepCopy().release(); + ++it_other; + } else { + NOTREACHED(); + } + } + + // Add extra PolicyMaps at the end. + while (it_other != end_other) { + PolicyMap*& policy = policy_bundle_[it_other->first]; + DCHECK(!policy); + policy = it_other->second->DeepCopy().release(); + ++it_other; + } +} + +bool PolicyBundle::Equals(const PolicyBundle& other) const { + // Equals() has the peculiarity that an entry with an empty PolicyMap equals + // an non-existant entry. This handles usage of non-const Get() that doesn't + // insert any policies. + const_iterator it_this = begin(); + const_iterator it_other = other.begin(); + + while (true) { + // Skip empty PolicyMaps. + while (it_this != end() && it_this->second->empty()) + ++it_this; + while (it_other != other.end() && it_other->second->empty()) + ++it_other; + if (it_this == end() || it_other == other.end()) + break; + if (it_this->first != it_other->first || + !it_this->second->Equals(*it_other->second)) { + return false; + } + ++it_this; + ++it_other; + } + return it_this == end() && it_other == other.end(); +} + +void PolicyBundle::Clear() { + STLDeleteValues(&policy_bundle_); +} + +} // namespace policy diff --git a/components/policy/core/common/policy_bundle.h b/components/policy/core/common/policy_bundle.h new file mode 100644 index 0000000..0266672 --- /dev/null +++ b/components/policy/core/common/policy_bundle.h @@ -0,0 +1,73 @@ +// Copyright 2013 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. + +#ifndef COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_ +#define COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_namespace.h" +#include "components/policy/policy_export.h" + +namespace policy { + +// Maps policy namespaces to PolicyMaps. +class POLICY_EXPORT PolicyBundle { + public: + typedef std::map<PolicyNamespace, PolicyMap*> MapType; + typedef MapType::iterator iterator; + typedef MapType::const_iterator const_iterator; + + PolicyBundle(); + virtual ~PolicyBundle(); + + // Returns the PolicyMap for namespace |ns|. + PolicyMap& Get(const PolicyNamespace& ns); + const PolicyMap& Get(const PolicyNamespace& ns) const; + + // Swaps the internal representation of |this| with |other|. + void Swap(PolicyBundle* other); + + // |this| becomes a copy of |other|. Any existing PolicyMaps are dropped. + void CopyFrom(const PolicyBundle& other); + + // Merges the PolicyMaps of |this| with those of |other| for each namespace + // in common. Also adds copies of the (namespace, PolicyMap) pairs in |other| + // that don't have an entry in |this|. + // Each policy in each PolicyMap is replaced only if the policy from |other| + // has a higher priority. + // See PolicyMap::MergeFrom for details on merging individual PolicyMaps. + void MergeFrom(const PolicyBundle& other); + + // Returns true if |other| has the same keys and value as |this|. + bool Equals(const PolicyBundle& other) const; + + // Returns iterators to the beginning and end of the underlying container. + iterator begin() { return policy_bundle_.begin(); } + iterator end() { return policy_bundle_.end(); } + + // These can be used to iterate over and read the PolicyMaps, but not to + // modify them. + const_iterator begin() const { return policy_bundle_.begin(); } + const_iterator end() const { return policy_bundle_.end(); } + + // Erases all the existing pairs. + void Clear(); + + private: + MapType policy_bundle_; + + // An empty PolicyMap that is returned by const Get() for namespaces that + // do not exist in |policy_bundle_|. + const PolicyMap kEmpty_; + + DISALLOW_COPY_AND_ASSIGN(PolicyBundle); +}; + +} // namespace policy + +#endif // COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_ diff --git a/components/policy/core/common/policy_bundle_unittest.cc b/components/policy/core/common/policy_bundle_unittest.cc new file mode 100644 index 0000000..bafa25e --- /dev/null +++ b/components/policy/core/common/policy_bundle_unittest.cc @@ -0,0 +1,260 @@ +// Copyright 2013 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 "components/policy/core/common/policy_bundle.h" + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "components/policy/core/common/external_data_fetcher.h" +#include "components/policy/core/common/policy_map.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +namespace { + +const char kPolicyClashing0[] = "policy-clashing-0"; +const char kPolicyClashing1[] = "policy-clashing-1"; +const char kPolicy0[] = "policy-0"; +const char kPolicy1[] = "policy-1"; +const char kPolicy2[] = "policy-2"; +const char kExtension0[] = "extension-0"; +const char kExtension1[] = "extension-1"; +const char kExtension2[] = "extension-2"; +const char kExtension3[] = "extension-3"; + +// Adds test policies to |policy|. +void AddTestPolicies(PolicyMap* policy) { + policy->Set("mandatory-user", POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, base::Value::CreateIntegerValue(123), NULL); + policy->Set("mandatory-machine", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + base::Value::CreateStringValue("omg"), NULL); + policy->Set("recommended-user", POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL); + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetBoolean("false", false); + dict->SetInteger("int", 456); + dict->SetString("str", "bbq"); + policy->Set("recommended-machine", POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_MACHINE, dict, NULL); +} + +// Adds test policies to |policy| based on the parameters: +// - kPolicyClashing0 mapped to |value|, user mandatory +// - kPolicyClashing1 mapped to |value|, with |level| and |scope| +// - |name| mapped to |value|, user mandatory +void AddTestPoliciesWithParams(PolicyMap *policy, + const char* name, + int value, + PolicyLevel level, + PolicyScope scope) { + policy->Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(value), NULL); + policy->Set(kPolicyClashing1, level, scope, + base::Value::CreateIntegerValue(value), NULL); + policy->Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(value), NULL); +} + +// Returns true if |bundle| is empty. +bool IsEmpty(const PolicyBundle& bundle) { + return bundle.begin() == bundle.end(); +} + +} // namespace + +TEST(PolicyBundleTest, Get) { + PolicyBundle bundle; + EXPECT_TRUE(IsEmpty(bundle)); + + AddTestPolicies(&bundle.Get( + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))); + EXPECT_FALSE(IsEmpty(bundle)); + + PolicyMap policy; + AddTestPolicies(&policy); + EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, + std::string())).Equals(policy)); + + PolicyBundle::const_iterator it = bundle.begin(); + ASSERT_TRUE(it != bundle.end()); + EXPECT_EQ(POLICY_DOMAIN_CHROME, it->first.domain); + EXPECT_EQ("", it->first.component_id); + ASSERT_TRUE(it->second); + EXPECT_TRUE(it->second->Equals(policy)); + ++it; + EXPECT_TRUE(it == bundle.end()); + EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension0)).empty()); + + EXPECT_FALSE(IsEmpty(bundle)); + bundle.Clear(); + EXPECT_TRUE(IsEmpty(bundle)); +} + +TEST(PolicyBundleTest, SwapAndCopy) { + PolicyBundle bundle0; + PolicyBundle bundle1; + + AddTestPolicies(&bundle0.Get( + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))); + AddTestPolicies(&bundle0.Get( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0))); + EXPECT_FALSE(IsEmpty(bundle0)); + EXPECT_TRUE(IsEmpty(bundle1)); + + PolicyMap policy; + AddTestPolicies(&policy); + EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, + std::string())).Equals(policy)); + EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension0)).Equals(policy)); + + bundle0.Swap(&bundle1); + EXPECT_TRUE(IsEmpty(bundle0)); + EXPECT_FALSE(IsEmpty(bundle1)); + + EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, + std::string())).Equals(policy)); + EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension0)).Equals(policy)); + + bundle0.CopyFrom(bundle1); + EXPECT_FALSE(IsEmpty(bundle0)); + EXPECT_FALSE(IsEmpty(bundle1)); + EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, + std::string())).Equals(policy)); + EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension0)).Equals(policy)); +} + +TEST(PolicyBundleTest, MergeFrom) { + // Each bundleN has kExtensionN. Each bundle also has policy for + // chrome and kExtension3. + // |bundle0| has the highest priority, |bundle2| the lowest. + PolicyBundle bundle0; + PolicyBundle bundle1; + PolicyBundle bundle2; + + PolicyMap policy0; + AddTestPoliciesWithParams( + &policy0, kPolicy0, 0u, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER); + bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .CopyFrom(policy0); + bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)) + .CopyFrom(policy0); + bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3)) + .CopyFrom(policy0); + + PolicyMap policy1; + AddTestPoliciesWithParams( + &policy1, kPolicy1, 1u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE); + bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .CopyFrom(policy1); + bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)) + .CopyFrom(policy1); + bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3)) + .CopyFrom(policy1); + + PolicyMap policy2; + AddTestPoliciesWithParams( + &policy2, kPolicy2, 2u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); + bundle2.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .CopyFrom(policy2); + bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2)) + .CopyFrom(policy2); + bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3)) + .CopyFrom(policy2); + + // Merge in order of decreasing priority. + PolicyBundle merged; + merged.MergeFrom(bundle0); + merged.MergeFrom(bundle1); + merged.MergeFrom(bundle2); + PolicyBundle empty_bundle; + merged.MergeFrom(empty_bundle); + + // chrome and kExtension3 policies are merged: + // - kPolicyClashing0 comes from bundle0, which has the highest priority; + // - kPolicyClashing1 comes from bundle1, which has the highest level/scope + // combination; + // - kPolicyN are merged from each bundle. + PolicyMap expected; + expected.Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(0), NULL); + expected.Set(kPolicyClashing1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + base::Value::CreateIntegerValue(1), NULL); + expected.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(0), NULL); + expected.Set(kPolicy1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(1), NULL); + expected.Set(kPolicy2, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(2), NULL); + EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, + std::string())).Equals(expected)); + EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension3)).Equals(expected)); + // extension0 comes only from bundle0. + EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension0)).Equals(policy0)); + // extension1 comes only from bundle1. + EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension1)).Equals(policy1)); + // extension2 comes only from bundle2. + EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, + kExtension2)).Equals(policy2)); +} + +TEST(PolicyBundleTest, Equals) { + PolicyBundle bundle; + AddTestPolicies(&bundle.Get( + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))); + AddTestPolicies(&bundle.Get( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0))); + + PolicyBundle other; + EXPECT_FALSE(bundle.Equals(other)); + other.CopyFrom(bundle); + EXPECT_TRUE(bundle.Equals(other)); + + AddTestPolicies(&bundle.Get( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1))); + EXPECT_FALSE(bundle.Equals(other)); + other.CopyFrom(bundle); + EXPECT_TRUE(bundle.Equals(other)); + AddTestPolicies(&other.Get( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2))); + EXPECT_FALSE(bundle.Equals(other)); + + other.CopyFrom(bundle); + bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .Set(kPolicy0, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(123), + NULL); + EXPECT_FALSE(bundle.Equals(other)); + other.CopyFrom(bundle); + EXPECT_TRUE(bundle.Equals(other)); + bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .Set(kPolicy0, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + base::Value::CreateIntegerValue(123), + NULL); + EXPECT_FALSE(bundle.Equals(other)); + + // Test non-const Get(). + bundle.Clear(); + other.Clear(); + PolicyMap& policy_map = + bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); + EXPECT_TRUE(bundle.Equals(other)); + policy_map.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + base::Value::CreateIntegerValue(123), NULL); + EXPECT_FALSE(bundle.Equals(other)); +} + +} // namespace policy |