summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authordconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-02 14:33:46 +0000
committerdconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-02 14:33:46 +0000
commitafefdcf4a25113f849908605c946ccfa6a914811 (patch)
treea50035aa981fd588561d99ec9166984698dbe92d /components
parentbed2900b838897a24c8a86a95fd93d8166c6928a (diff)
downloadchromium_src-afefdcf4a25113f849908605c946ccfa6a914811.zip
chromium_src-afefdcf4a25113f849908605c946ccfa6a914811.tar.gz
chromium_src-afefdcf4a25113f849908605c946ccfa6a914811.tar.bz2
Move ConfigurationPolicyProvider, etc. to components/policy.
This facilitates the refactoring of chrome/browser/policy into a layered component. BUG=271392 NOTRY=true Review URL: https://codereview.chromium.org/92153002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238097 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/components_tests.gyp3
-rw-r--r--components/policy.gypi35
-rw-r--r--components/policy/core/common/configuration_policy_provider.cc76
-rw-r--r--components/policy/core/common/configuration_policy_provider.h103
-rw-r--r--components/policy/core/common/configuration_policy_provider_test.cc403
-rw-r--r--components/policy/core/common/configuration_policy_provider_test.h152
-rw-r--r--components/policy/core/common/mock_configuration_policy_provider.cc47
-rw-r--r--components/policy/core/common/mock_configuration_policy_provider.h66
8 files changed, 883 insertions, 2 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 81e65a4..3e33547 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -174,6 +174,9 @@
},
}],
['configuration_policy==1', {
+ 'dependencies': [
+ 'components.gyp:policy_test_support',
+ ],
'sources': [
'policy/core/common/policy_bundle_unittest.cc',
'policy/core/common/policy_map_unittest.cc',
diff --git a/components/policy.gypi b/components/policy.gypi
index 4580dea..17b5cf9 100644
--- a/components/policy.gypi
+++ b/components/policy.gypi
@@ -21,11 +21,13 @@
'conditions': [
['configuration_policy==1', {
'sources': [
- 'policy/core/common/policy_bundle.cc',
- 'policy/core/common/policy_bundle.h',
+ 'policy/core/common/configuration_policy_provider.cc',
+ 'policy/core/common/configuration_policy_provider.h',
'policy/core/common/external_data_fetcher.cc',
'policy/core/common/external_data_fetcher.h',
'policy/core/common/external_data_manager.h',
+ 'policy/core/common/policy_bundle.cc',
+ 'policy/core/common/policy_bundle.h',
'policy/core/common/policy_details.h',
'policy/core/common/policy_namespace.cc',
'policy/core/common/policy_namespace.h',
@@ -64,4 +66,33 @@
],
},
],
+ 'conditions': [
+ ['configuration_policy==1', {
+ 'targets': [
+ {
+ 'target_name': 'policy_test_support',
+ 'type': 'static_library',
+ # This must be undefined so that POLICY_EXPORT works correctly in
+ # the static_library build.
+ 'defines!': [
+ 'POLICY_COMPONENT_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ 'policy_component',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'policy/core/common/configuration_policy_provider_test.cc',
+ 'policy/core/common/configuration_policy_provider_test.h',
+ 'policy/core/common/mock_configuration_policy_provider.cc',
+ 'policy/core/common/mock_configuration_policy_provider.h',
+ ],
+ },
+ ],
+ }],
+ ],
}
diff --git a/components/policy/core/common/configuration_policy_provider.cc b/components/policy/core/common/configuration_policy_provider.cc
new file mode 100644
index 0000000..01070c8
--- /dev/null
+++ b/components/policy/core/common/configuration_policy_provider.cc
@@ -0,0 +1,76 @@
+// 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/configuration_policy_provider.h"
+
+#include "base/callback.h"
+#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/policy_map.h"
+
+namespace policy {
+
+ConfigurationPolicyProvider::Observer::~Observer() {}
+
+ConfigurationPolicyProvider::ConfigurationPolicyProvider()
+ : did_shutdown_(false),
+ schema_registry_(NULL) {}
+
+ConfigurationPolicyProvider::~ConfigurationPolicyProvider() {
+ DCHECK(did_shutdown_);
+}
+
+void ConfigurationPolicyProvider::Init(SchemaRegistry* registry) {
+ schema_registry_ = registry;
+ schema_registry_->AddObserver(this);
+}
+
+void ConfigurationPolicyProvider::Shutdown() {
+ did_shutdown_ = true;
+ if (schema_registry_) {
+ // Unit tests don't initialize the BrowserPolicyConnector but call
+ // shutdown; handle that.
+ schema_registry_->RemoveObserver(this);
+ schema_registry_ = NULL;
+ }
+}
+
+bool ConfigurationPolicyProvider::IsInitializationComplete(
+ PolicyDomain domain) const {
+ return true;
+}
+
+void ConfigurationPolicyProvider::UpdatePolicy(
+ scoped_ptr<PolicyBundle> bundle) {
+ if (bundle.get())
+ policy_bundle_.Swap(bundle.get());
+ else
+ policy_bundle_.Clear();
+ FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
+ observer_list_,
+ OnUpdatePolicy(this));
+}
+
+SchemaRegistry* ConfigurationPolicyProvider::schema_registry() const {
+ return schema_registry_;
+}
+
+const scoped_refptr<SchemaMap>&
+ConfigurationPolicyProvider::schema_map() const {
+ return schema_registry_->schema_map();
+}
+
+void ConfigurationPolicyProvider::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ConfigurationPolicyProvider::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void ConfigurationPolicyProvider::OnSchemaRegistryUpdated(
+ bool has_new_schemas) {}
+
+void ConfigurationPolicyProvider::OnSchemaRegistryReady() {}
+
+} // namespace policy
diff --git a/components/policy/core/common/configuration_policy_provider.h b/components/policy/core/common/configuration_policy_provider.h
new file mode 100644
index 0000000..f2b746d
--- /dev/null
+++ b/components/policy/core/common/configuration_policy_provider.h
@@ -0,0 +1,103 @@
+// 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_CONFIGURATION_POLICY_PROVIDER_H_
+#define COMPONENTS_POLICY_CORE_COMMON_CONFIGURATION_POLICY_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "components/policy/core/common/policy_bundle.h"
+#include "components/policy/core/common/policy_namespace.h"
+#include "components/policy/core/common/schema_registry.h"
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+// A mostly-abstract super class for platform-specific policy providers.
+// Platform-specific policy providers (Windows Group Policy, gconf,
+// etc.) should implement a subclass of this class.
+class POLICY_EXPORT ConfigurationPolicyProvider
+ : public SchemaRegistry::Observer {
+ public:
+ class POLICY_EXPORT Observer {
+ public:
+ virtual ~Observer();
+ virtual void OnUpdatePolicy(ConfigurationPolicyProvider* provider) = 0;
+ };
+
+ ConfigurationPolicyProvider();
+
+ // Policy providers can be deleted quite late during shutdown of the browser,
+ // and it's not guaranteed that the message loops will still be running when
+ // this is invoked. Override Shutdown() instead for cleanup code that needs
+ // to post to the FILE thread, for example.
+ virtual ~ConfigurationPolicyProvider();
+
+ // Invoked as soon as the main message loops are spinning. Policy providers
+ // are created early during startup to provide the initial policies; the
+ // Init() call allows them to perform initialization tasks that require
+ // running message loops.
+ // The policy provider will load policy for the components registered in
+ // the |schema_registry| whose domain is supported by this provider.
+ virtual void Init(SchemaRegistry* registry);
+
+ // Must be invoked before deleting the provider. Implementations can override
+ // this method to do appropriate cleanup while threads are still running, and
+ // must also invoke ConfigurationPolicyProvider::Shutdown().
+ // The provider should keep providing the current policies after Shutdown()
+ // is invoked, it only has to stop updating.
+ virtual void Shutdown();
+
+ // Returns the current PolicyBundle.
+ const PolicyBundle& policies() const { return policy_bundle_; }
+
+ // Check whether this provider has completed initialization for the given
+ // policy |domain|. This is used to detect whether initialization is done in
+ // case implementations need to do asynchronous operations for initialization.
+ virtual bool IsInitializationComplete(PolicyDomain domain) const;
+
+ // Asks the provider to refresh its policies. All the updates caused by this
+ // call will be visible on the next call of OnUpdatePolicy on the observers,
+ // which are guaranteed to happen even if the refresh fails.
+ // It is possible that Shutdown() is called first though, and
+ // OnUpdatePolicy won't be called if that happens.
+ virtual void RefreshPolicies() = 0;
+
+ // Observers must detach themselves before the provider is deleted.
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+
+ // SchemaRegistry::Observer:
+ virtual void OnSchemaRegistryUpdated(bool has_new_schemas) OVERRIDE;
+ virtual void OnSchemaRegistryReady() OVERRIDE;
+
+ protected:
+ // Subclasses must invoke this to update the policies currently served by
+ // this provider. UpdatePolicy() takes ownership of |policies|.
+ // The observers are notified after the policies are updated.
+ void UpdatePolicy(scoped_ptr<PolicyBundle> bundle);
+
+ SchemaRegistry* schema_registry() const;
+
+ const scoped_refptr<SchemaMap>& schema_map() const;
+
+ private:
+ // The policies currently configured at this provider.
+ PolicyBundle policy_bundle_;
+
+ // Whether Shutdown() has been invoked.
+ bool did_shutdown_;
+
+ SchemaRegistry* schema_registry_;
+
+ ObserverList<Observer, true> observer_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProvider);
+};
+
+} // namespace policy
+
+#endif // COMPONENTS_POLICY_CORE_COMMON_CONFIGURATION_POLICY_PROVIDER_H_
diff --git a/components/policy/core/common/configuration_policy_provider_test.cc b/components/policy/core/common/configuration_policy_provider_test.cc
new file mode 100644
index 0000000..8c5ef32
--- /dev/null
+++ b/components/policy/core/common/configuration_policy_provider_test.cc
@@ -0,0 +1,403 @@
+// 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/configuration_policy_provider_test.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/values.h"
+#include "components/policy/core/common/configuration_policy_provider.h"
+#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/core/common/policy_bundle.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::Mock;
+using ::testing::_;
+
+namespace policy {
+
+const char kTestChromeSchema[] =
+ "{"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"StringPolicy\": { \"type\": \"string\" },"
+ " \"BooleanPolicy\": { \"type\": \"boolean\" },"
+ " \"IntegerPolicy\": { \"type\": \"integer\" },"
+ " \"StringListPolicy\": {"
+ " \"type\": \"array\","
+ " \"items\": { \"type\": \"string\" }"
+ " },"
+ " \"DictionaryPolicy\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"bool\": { \"type\": \"boolean\" },"
+ " \"double\": { \"type\": \"number\" },"
+ " \"int\": { \"type\": \"integer\" },"
+ " \"string\": { \"type\": \"string\" },"
+ " \"array\": {"
+ " \"type\": \"array\","
+ " \"items\": { \"type\": \"string\" }"
+ " },"
+ " \"dictionary\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"sub\": { \"type\": \"string\" },"
+ " \"sublist\": {"
+ " \"type\": \"array\","
+ " \"items\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"aaa\": { \"type\": \"integer\" },"
+ " \"bbb\": { \"type\": \"integer\" },"
+ " \"ccc\": { \"type\": \"string\" },"
+ " \"ddd\": { \"type\": \"string\" }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " },"
+ " \"list\": {"
+ " \"type\": \"array\","
+ " \"items\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"subdictindex\": { \"type\": \"integer\" },"
+ " \"subdict\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"bool\": { \"type\": \"boolean\" },"
+ " \"double\": { \"type\": \"number\" },"
+ " \"int\": { \"type\": \"integer\" },"
+ " \"string\": { \"type\": \"string\" }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " },"
+ " \"dict\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"bool\": { \"type\": \"boolean\" },"
+ " \"double\": { \"type\": \"number\" },"
+ " \"int\": { \"type\": \"integer\" },"
+ " \"string\": { \"type\": \"string\" },"
+ " \"list\": {"
+ " \"type\": \"array\","
+ " \"items\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"subdictindex\": { \"type\": \"integer\" },"
+ " \"subdict\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"bool\": { \"type\": \"boolean\" },"
+ " \"double\": { \"type\": \"number\" },"
+ " \"int\": { \"type\": \"integer\" },"
+ " \"string\": { \"type\": \"string\" }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ "}";
+
+namespace test_keys {
+
+const char kKeyString[] = "StringPolicy";
+const char kKeyBoolean[] = "BooleanPolicy";
+const char kKeyInteger[] = "IntegerPolicy";
+const char kKeyStringList[] = "StringListPolicy";
+const char kKeyDictionary[] = "DictionaryPolicy";
+
+} // namespace test_keys
+
+PolicyTestBase::PolicyTestBase() {}
+
+PolicyTestBase::~PolicyTestBase() {}
+
+void PolicyTestBase::SetUp() {
+ std::string error;
+ chrome_schema_ = Schema::Parse(kTestChromeSchema, &error);
+ ASSERT_TRUE(chrome_schema_.valid()) << error;
+ schema_registry_.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_CHROME, ""),
+ chrome_schema_);
+}
+
+void PolicyTestBase::TearDown() {
+ loop_.RunUntilIdle();
+}
+
+PolicyProviderTestHarness::PolicyProviderTestHarness(PolicyLevel level,
+ PolicyScope scope)
+ : level_(level), scope_(scope) {}
+
+PolicyProviderTestHarness::~PolicyProviderTestHarness() {}
+
+PolicyLevel PolicyProviderTestHarness::policy_level() const {
+ return level_;
+}
+
+PolicyScope PolicyProviderTestHarness::policy_scope() const {
+ return scope_;
+}
+
+void PolicyProviderTestHarness::Install3rdPartyPolicy(
+ const base::DictionaryValue* policies) {
+ FAIL();
+}
+
+ConfigurationPolicyProviderTest::ConfigurationPolicyProviderTest() {}
+
+ConfigurationPolicyProviderTest::~ConfigurationPolicyProviderTest() {}
+
+void ConfigurationPolicyProviderTest::SetUp() {
+ PolicyTestBase::SetUp();
+
+ test_harness_.reset((*GetParam())());
+ test_harness_->SetUp();
+
+ Schema extension_schema =
+ chrome_schema_.GetKnownProperty(test_keys::kKeyDictionary);
+ ASSERT_TRUE(extension_schema.valid());
+ schema_registry_.RegisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ extension_schema);
+ schema_registry_.RegisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ extension_schema);
+ schema_registry_.RegisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ "cccccccccccccccccccccccccccccccc"),
+ extension_schema);
+
+ provider_.reset(test_harness_->CreateProvider(&schema_registry_,
+ loop_.message_loop_proxy()));
+ provider_->Init(&schema_registry_);
+ // Some providers do a reload on init. Make sure any notifications generated
+ // are fired now.
+ loop_.RunUntilIdle();
+
+ const PolicyBundle kEmptyBundle;
+ EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
+}
+
+void ConfigurationPolicyProviderTest::TearDown() {
+ // Give providers the chance to clean up after themselves on the file thread.
+ provider_->Shutdown();
+ provider_.reset();
+
+ PolicyTestBase::TearDown();
+}
+
+void ConfigurationPolicyProviderTest::CheckValue(
+ const char* policy_name,
+ const base::Value& expected_value,
+ base::Closure install_value) {
+ // Install the value, reload policy and check the provider for the value.
+ install_value.Run();
+ provider_->RefreshPolicies();
+ loop_.RunUntilIdle();
+ PolicyBundle expected_bundle;
+ expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .Set(policy_name,
+ test_harness_->policy_level(),
+ test_harness_->policy_scope(),
+ expected_value.DeepCopy(),
+ NULL);
+ EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
+ // TODO(joaodasilva): set the policy in the POLICY_DOMAIN_EXTENSIONS too,
+ // and extend the |expected_bundle|, once all providers are ready.
+}
+
+TEST_P(ConfigurationPolicyProviderTest, Empty) {
+ provider_->RefreshPolicies();
+ loop_.RunUntilIdle();
+ const PolicyBundle kEmptyBundle;
+ EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, StringValue) {
+ const char kTestString[] = "string_value";
+ base::StringValue expected_value(kTestString);
+ CheckValue(test_keys::kKeyString,
+ expected_value,
+ base::Bind(&PolicyProviderTestHarness::InstallStringPolicy,
+ base::Unretained(test_harness_.get()),
+ test_keys::kKeyString,
+ kTestString));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, BooleanValue) {
+ base::FundamentalValue expected_value(true);
+ CheckValue(test_keys::kKeyBoolean,
+ expected_value,
+ base::Bind(&PolicyProviderTestHarness::InstallBooleanPolicy,
+ base::Unretained(test_harness_.get()),
+ test_keys::kKeyBoolean,
+ true));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, IntegerValue) {
+ base::FundamentalValue expected_value(42);
+ CheckValue(test_keys::kKeyInteger,
+ expected_value,
+ base::Bind(&PolicyProviderTestHarness::InstallIntegerPolicy,
+ base::Unretained(test_harness_.get()),
+ test_keys::kKeyInteger,
+ 42));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, StringListValue) {
+ base::ListValue expected_value;
+ expected_value.Set(0U, base::Value::CreateStringValue("first"));
+ expected_value.Set(1U, base::Value::CreateStringValue("second"));
+ CheckValue(test_keys::kKeyStringList,
+ expected_value,
+ base::Bind(&PolicyProviderTestHarness::InstallStringListPolicy,
+ base::Unretained(test_harness_.get()),
+ test_keys::kKeyStringList,
+ &expected_value));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, DictionaryValue) {
+ base::DictionaryValue expected_value;
+ expected_value.SetBoolean("bool", true);
+ expected_value.SetDouble("double", 123.456);
+ expected_value.SetInteger("int", 123);
+ expected_value.SetString("string", "omg");
+
+ base::ListValue* list = new base::ListValue();
+ list->Set(0U, base::Value::CreateStringValue("first"));
+ list->Set(1U, base::Value::CreateStringValue("second"));
+ expected_value.Set("array", list);
+
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString("sub", "value");
+ list = new base::ListValue();
+ base::DictionaryValue* sub = new base::DictionaryValue();
+ sub->SetInteger("aaa", 111);
+ sub->SetInteger("bbb", 222);
+ list->Append(sub);
+ sub = new base::DictionaryValue();
+ sub->SetString("ccc", "333");
+ sub->SetString("ddd", "444");
+ list->Append(sub);
+ dict->Set("sublist", list);
+ expected_value.Set("dictionary", dict);
+
+ CheckValue(test_keys::kKeyDictionary,
+ expected_value,
+ base::Bind(&PolicyProviderTestHarness::InstallDictionaryPolicy,
+ base::Unretained(test_harness_.get()),
+ test_keys::kKeyDictionary,
+ &expected_value));
+}
+
+TEST_P(ConfigurationPolicyProviderTest, RefreshPolicies) {
+ PolicyBundle bundle;
+ EXPECT_TRUE(provider_->policies().Equals(bundle));
+
+ // OnUpdatePolicy is called even when there are no changes.
+ MockConfigurationPolicyObserver observer;
+ provider_->AddObserver(&observer);
+ EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
+ provider_->RefreshPolicies();
+ loop_.RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_TRUE(provider_->policies().Equals(bundle));
+
+ // OnUpdatePolicy is called when there are changes.
+ test_harness_->InstallStringPolicy(test_keys::kKeyString, "value");
+ EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
+ provider_->RefreshPolicies();
+ loop_.RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&observer);
+
+ bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .Set(test_keys::kKeyString,
+ test_harness_->policy_level(),
+ test_harness_->policy_scope(),
+ base::Value::CreateStringValue("value"),
+ NULL);
+ EXPECT_TRUE(provider_->policies().Equals(bundle));
+ provider_->RemoveObserver(&observer);
+}
+
+Configuration3rdPartyPolicyProviderTest::
+ Configuration3rdPartyPolicyProviderTest() {}
+
+Configuration3rdPartyPolicyProviderTest::
+ ~Configuration3rdPartyPolicyProviderTest() {}
+
+TEST_P(Configuration3rdPartyPolicyProviderTest, Load3rdParty) {
+ base::DictionaryValue policy_dict;
+ policy_dict.SetBoolean("bool", true);
+ policy_dict.SetDouble("double", 123.456);
+ policy_dict.SetInteger("int", 789);
+ policy_dict.SetString("string", "string value");
+
+ base::ListValue* list = new base::ListValue();
+ for (int i = 0; i < 2; ++i) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("subdictindex", i);
+ dict->Set("subdict", policy_dict.DeepCopy());
+ list->Append(dict);
+ }
+ policy_dict.Set("list", list);
+ policy_dict.Set("dict", policy_dict.DeepCopy());
+
+ // Install these policies as a Chrome policy.
+ test_harness_->InstallDictionaryPolicy(test_keys::kKeyDictionary,
+ &policy_dict);
+ // Install them as 3rd party policies too.
+ base::DictionaryValue policy_3rdparty;
+ policy_3rdparty.Set("extensions.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ policy_dict.DeepCopy());
+ policy_3rdparty.Set("extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ policy_dict.DeepCopy());
+ // Install invalid 3rd party policies that shouldn't be loaded. These also
+ // help detecting memory leaks in the code paths that detect invalid input.
+ policy_3rdparty.Set("invalid-domain.component", policy_dict.DeepCopy());
+ policy_3rdparty.Set("extensions.cccccccccccccccccccccccccccccccc",
+ base::Value::CreateStringValue("invalid-value"));
+ test_harness_->Install3rdPartyPolicy(&policy_3rdparty);
+
+ provider_->RefreshPolicies();
+ loop_.RunUntilIdle();
+
+ PolicyMap expected_policy;
+ expected_policy.Set(test_keys::kKeyDictionary,
+ test_harness_->policy_level(),
+ test_harness_->policy_scope(),
+ policy_dict.DeepCopy(),
+ NULL);
+ PolicyBundle expected_bundle;
+ expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .CopyFrom(expected_policy);
+ expected_policy.Clear();
+ expected_policy.LoadFrom(&policy_dict,
+ test_harness_->policy_level(),
+ test_harness_->policy_scope());
+ expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
+ .CopyFrom(expected_policy);
+ expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
+ .CopyFrom(expected_policy);
+ EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
+}
+
+} // namespace policy
diff --git a/components/policy/core/common/configuration_policy_provider_test.h b/components/policy/core/common/configuration_policy_provider_test.h
new file mode 100644
index 0000000..b0dc6d4
--- /dev/null
+++ b/components/policy/core/common/configuration_policy_provider_test.h
@@ -0,0 +1,152 @@
+// 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_CONFIGURATION_POLICY_PROVIDER_TEST_H_
+#define COMPONENTS_POLICY_CORE_COMMON_CONFIGURATION_POLICY_PROVIDER_TEST_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "components/policy/core/common/policy_types.h"
+#include "components/policy/core/common/schema.h"
+#include "components/policy/core/common/schema_registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class SequencedTaskRunner;
+class Value;
+}
+
+namespace policy {
+
+class ConfigurationPolicyProvider;
+
+namespace test_keys {
+
+extern const char kKeyString[];
+extern const char kKeyBoolean[];
+extern const char kKeyInteger[];
+extern const char kKeyStringList[];
+extern const char kKeyDictionary[];
+
+} // namespace test_keys
+
+class PolicyTestBase : public testing::Test {
+ public:
+ PolicyTestBase();
+ virtual ~PolicyTestBase();
+
+ // testing::Test:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ Schema chrome_schema_;
+ SchemaRegistry schema_registry_;
+
+ // Create an actual IO loop (needed by FilePathWatcher).
+ base::MessageLoopForIO loop_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PolicyTestBase);
+};
+
+// An interface for creating a test policy provider and creating a policy
+// provider instance for testing. Used as the parameter to the abstract
+// ConfigurationPolicyProviderTest below.
+class PolicyProviderTestHarness {
+ public:
+ // |level| and |scope| are the level and scope of the policies returned by
+ // the providers from CreateProvider().
+ PolicyProviderTestHarness(PolicyLevel level, PolicyScope scope);
+ virtual ~PolicyProviderTestHarness();
+
+ // Actions to run at gtest SetUp() time.
+ virtual void SetUp() = 0;
+
+ // Create a new policy provider.
+ virtual ConfigurationPolicyProvider* CreateProvider(
+ SchemaRegistry* registry,
+ scoped_refptr<base::SequencedTaskRunner> task_runner) = 0;
+
+ // Returns the policy level and scope set by the policy provider.
+ PolicyLevel policy_level() const;
+ PolicyScope policy_scope() const;
+
+ // Helpers to configure the environment the policy provider reads from.
+ virtual void InstallEmptyPolicy() = 0;
+ virtual void InstallStringPolicy(const std::string& policy_name,
+ const std::string& policy_value) = 0;
+ virtual void InstallIntegerPolicy(const std::string& policy_name,
+ int policy_value) = 0;
+ virtual void InstallBooleanPolicy(const std::string& policy_name,
+ bool policy_value) = 0;
+ virtual void InstallStringListPolicy(const std::string& policy_name,
+ const base::ListValue* policy_value) = 0;
+ virtual void InstallDictionaryPolicy(
+ const std::string& policy_name,
+ const base::DictionaryValue* policy_value) = 0;
+
+ // Not every provider supports installing 3rd party policy. Those who do
+ // should override this method; the default just makes the test fail.
+ virtual void Install3rdPartyPolicy(const base::DictionaryValue* policies);
+
+ private:
+ PolicyLevel level_;
+ PolicyScope scope_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyProviderTestHarness);
+};
+
+// A factory method for creating a test harness.
+typedef PolicyProviderTestHarness* (*CreatePolicyProviderTestHarness)();
+
+// Abstract policy provider test. This is meant to be instantiated for each
+// policy provider implementation, passing in a suitable harness factory
+// function as the test parameter.
+class ConfigurationPolicyProviderTest
+ : public PolicyTestBase,
+ public testing::WithParamInterface<CreatePolicyProviderTestHarness> {
+ protected:
+ ConfigurationPolicyProviderTest();
+ virtual ~ConfigurationPolicyProviderTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ // Installs a valid policy and checks whether the provider returns the
+ // |expected_value|.
+ void CheckValue(const char* policy_name,
+ const base::Value& expected_value,
+ base::Closure install_value);
+
+ scoped_ptr<PolicyProviderTestHarness> test_harness_;
+ scoped_ptr<ConfigurationPolicyProvider> provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderTest);
+};
+
+// An extension of ConfigurationPolicyProviderTest that also tests loading of
+// 3rd party policy. Policy provider implementations that support loading of
+// 3rd party policy should also instantiate these tests.
+class Configuration3rdPartyPolicyProviderTest
+ : public ConfigurationPolicyProviderTest {
+ protected:
+ Configuration3rdPartyPolicyProviderTest();
+ virtual ~Configuration3rdPartyPolicyProviderTest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Configuration3rdPartyPolicyProviderTest);
+};
+
+} // namespace policy
+
+#endif // COMPONENTS_POLICY_CORE_COMMON_CONFIGURATION_POLICY_PROVIDER_TEST_H_
diff --git a/components/policy/core/common/mock_configuration_policy_provider.cc b/components/policy/core/common/mock_configuration_policy_provider.cc
new file mode 100644
index 0000000..387b8d4
--- /dev/null
+++ b/components/policy/core/common/mock_configuration_policy_provider.cc
@@ -0,0 +1,47 @@
+// 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/mock_configuration_policy_provider.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/policy/core/common/policy_bundle.h"
+
+using testing::Invoke;
+
+namespace policy {
+
+MockConfigurationPolicyProvider::MockConfigurationPolicyProvider() {}
+
+MockConfigurationPolicyProvider::~MockConfigurationPolicyProvider() {}
+
+void MockConfigurationPolicyProvider::UpdateChromePolicy(
+ const PolicyMap& policy) {
+ scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
+ bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .CopyFrom(policy);
+ UpdatePolicy(bundle.Pass());
+ if (base::MessageLoop::current())
+ base::RunLoop().RunUntilIdle();
+}
+
+void MockConfigurationPolicyProvider::SetAutoRefresh() {
+ EXPECT_CALL(*this, RefreshPolicies()).WillRepeatedly(
+ Invoke(this, &MockConfigurationPolicyProvider::RefreshWithSamePolicies));
+}
+
+void MockConfigurationPolicyProvider::RefreshWithSamePolicies() {
+ scoped_ptr<PolicyBundle> bundle(new PolicyBundle);
+ bundle->CopyFrom(policies());
+ UpdatePolicy(bundle.Pass());
+}
+
+MockConfigurationPolicyObserver::MockConfigurationPolicyObserver() {}
+
+MockConfigurationPolicyObserver::~MockConfigurationPolicyObserver() {}
+
+} // namespace policy
diff --git a/components/policy/core/common/mock_configuration_policy_provider.h b/components/policy/core/common/mock_configuration_policy_provider.h
new file mode 100644
index 0000000..d891140
--- /dev/null
+++ b/components/policy/core/common/mock_configuration_policy_provider.h
@@ -0,0 +1,66 @@
+// 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_MOCK_CONFIGURATION_POLICY_PROVIDER_H_
+#define COMPONENTS_POLICY_CORE_COMMON_MOCK_CONFIGURATION_POLICY_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "components/policy/core/common/configuration_policy_provider.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/schema_registry.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace policy {
+
+// Mock ConfigurationPolicyProvider implementation that supplies canned
+// values for polices.
+// TODO(joaodasilva, mnissler): introduce an implementation that non-policy
+// code can use that doesn't require the usual boilerplate.
+// http://crbug.com/242087
+class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider {
+ public:
+ MockConfigurationPolicyProvider();
+ virtual ~MockConfigurationPolicyProvider();
+
+ MOCK_CONST_METHOD1(IsInitializationComplete, bool(PolicyDomain domain));
+ MOCK_METHOD0(RefreshPolicies, void());
+
+ // Make public for tests.
+ using ConfigurationPolicyProvider::UpdatePolicy;
+
+ // Utility method that invokes UpdatePolicy() with a PolicyBundle that maps
+ // the Chrome namespace to a copy of |policy|.
+ void UpdateChromePolicy(const PolicyMap& policy);
+
+ // Convenience method so that tests don't need to create a registry to create
+ // this mock.
+ using ConfigurationPolicyProvider::Init;
+ void Init() {
+ ConfigurationPolicyProvider::Init(&registry_);
+ }
+
+ // Convenience method that installs an expectation on RefreshPolicies that
+ // just notifies the observers and serves the same policies.
+ void SetAutoRefresh();
+
+ private:
+ void RefreshWithSamePolicies();
+
+ SchemaRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockConfigurationPolicyProvider);
+};
+
+class MockConfigurationPolicyObserver
+ : public ConfigurationPolicyProvider::Observer {
+ public:
+ MockConfigurationPolicyObserver();
+ virtual ~MockConfigurationPolicyObserver();
+
+ MOCK_METHOD1(OnUpdatePolicy, void(ConfigurationPolicyProvider*));
+};
+
+} // namespace policy
+
+#endif // COMPONENTS_POLICY_CORE_COMMON_MOCK_CONFIGURATION_POLICY_PROVIDER_H_