blob: 5e1db90049a4ca123ee83939ccbcc310f90f4c96 [file] [log] [blame]
// Copyright (c) 2012 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/config_dir_policy_loader.h"
#include <utility>
#include "base/compiler_specific.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_string_value_serializer.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "components/policy/core/common/async_policy_provider.h"
#include "components/policy/core/common/configuration_policy_provider_test.h"
#include "components/policy/core/common/policy_bundle.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
namespace policy {
namespace {
// Subdirectory of the config dir that contains mandatory policies.
const base::FilePath::CharType kMandatoryPath[] = FILE_PATH_LITERAL("managed");
class TestHarness : public PolicyProviderTestHarness {
public:
TestHarness();
~TestHarness() override;
void SetUp() override;
ConfigurationPolicyProvider* CreateProvider(
SchemaRegistry* registry,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
void InstallEmptyPolicy() override;
void InstallStringPolicy(const std::string& policy_name,
const std::string& policy_value) override;
void InstallIntegerPolicy(const std::string& policy_name,
int policy_value) override;
void InstallBooleanPolicy(const std::string& policy_name,
bool policy_value) override;
void InstallStringListPolicy(const std::string& policy_name,
const base::ListValue* policy_value) override;
void InstallDictionaryPolicy(
const std::string& policy_name,
const base::DictionaryValue* policy_value) override;
void Install3rdPartyPolicy(const base::DictionaryValue* policies) override;
const base::FilePath& test_dir() { return test_dir_.GetPath(); }
// JSON-encode a dictionary and write it to a file.
void WriteConfigFile(const base::DictionaryValue& dict,
const std::string& file_name);
// Returns a unique name for a policy file. Each subsequent call returns a new
// name that comes lexicographically after the previous one.
std::string NextConfigFileName();
static PolicyProviderTestHarness* Create();
private:
base::ScopedTempDir test_dir_;
int next_policy_file_index_;
DISALLOW_COPY_AND_ASSIGN(TestHarness);
};
TestHarness::TestHarness()
: PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM),
next_policy_file_index_(100) {}
TestHarness::~TestHarness() {}
void TestHarness::SetUp() {
ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
}
ConfigurationPolicyProvider* TestHarness::CreateProvider(
SchemaRegistry* registry,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
std::unique_ptr<AsyncPolicyLoader> loader(
new ConfigDirPolicyLoader(task_runner, test_dir(), POLICY_SCOPE_MACHINE));
return new AsyncPolicyProvider(registry, std::move(loader));
}
void TestHarness::InstallEmptyPolicy() {
base::DictionaryValue dict;
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::InstallStringPolicy(const std::string& policy_name,
const std::string& policy_value) {
base::DictionaryValue dict;
dict.SetString(policy_name, policy_value);
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::InstallIntegerPolicy(const std::string& policy_name,
int policy_value) {
base::DictionaryValue dict;
dict.SetInteger(policy_name, policy_value);
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::InstallBooleanPolicy(const std::string& policy_name,
bool policy_value) {
base::DictionaryValue dict;
dict.SetBoolean(policy_name, policy_value);
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::InstallStringListPolicy(const std::string& policy_name,
const base::ListValue* policy_value) {
base::DictionaryValue dict;
dict.Set(policy_name, base::MakeUnique<base::Value>(*policy_value));
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::InstallDictionaryPolicy(
const std::string& policy_name,
const base::DictionaryValue* policy_value) {
base::DictionaryValue dict;
dict.Set(policy_name, base::MakeUnique<base::Value>(*policy_value));
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) {
base::DictionaryValue dict;
dict.Set("3rdparty", base::MakeUnique<base::Value>(*policies));
WriteConfigFile(dict, NextConfigFileName());
}
void TestHarness::WriteConfigFile(const base::DictionaryValue& dict,
const std::string& file_name) {
std::string data;
JSONStringValueSerializer serializer(&data);
serializer.Serialize(dict);
const base::FilePath mandatory_dir(test_dir().Append(kMandatoryPath));
ASSERT_TRUE(base::CreateDirectory(mandatory_dir));
const base::FilePath file_path(mandatory_dir.AppendASCII(file_name));
ASSERT_EQ((int) data.size(),
base::WriteFile(file_path, data.c_str(), data.size()));
}
std::string TestHarness::NextConfigFileName() {
EXPECT_LE(next_policy_file_index_, 999);
return std::string("policy") + base::IntToString(next_policy_file_index_++);
}
// static
PolicyProviderTestHarness* TestHarness::Create() {
return new TestHarness();
}
} // namespace
// Instantiate abstract test case for basic policy reading tests.
INSTANTIATE_TEST_CASE_P(
ConfigDirPolicyLoaderTest,
ConfigurationPolicyProviderTest,
testing::Values(TestHarness::Create));
// Instantiate abstract test case for 3rd party policy reading tests.
INSTANTIATE_TEST_CASE_P(
ConfigDir3rdPartyPolicyLoaderTest,
Configuration3rdPartyPolicyProviderTest,
testing::Values(TestHarness::Create));
// Some tests that exercise special functionality in ConfigDirPolicyLoader.
class ConfigDirPolicyLoaderTest : public PolicyTestBase {
protected:
void SetUp() override {
PolicyTestBase::SetUp();
harness_.SetUp();
}
TestHarness harness_;
};
// The preferences dictionary is expected to be empty when there are no files to
// load.
TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
ConfigDirPolicyLoader loader(loop_.task_runner(), harness_.test_dir(),
POLICY_SCOPE_MACHINE);
std::unique_ptr<PolicyBundle> bundle(loader.Load());
ASSERT_TRUE(bundle.get());
const PolicyBundle kEmptyBundle;
EXPECT_TRUE(bundle->Equals(kEmptyBundle));
}
// Reading from a non-existent directory should result in an empty preferences
// dictionary.
TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) {
base::FilePath non_existent_dir(
harness_.test_dir().Append(FILE_PATH_LITERAL("not_there")));
ConfigDirPolicyLoader loader(loop_.task_runner(), non_existent_dir,
POLICY_SCOPE_MACHINE);
std::unique_ptr<PolicyBundle> bundle(loader.Load());
ASSERT_TRUE(bundle.get());
const PolicyBundle kEmptyBundle;
EXPECT_TRUE(bundle->Equals(kEmptyBundle));
}
// Test merging values from different files.
TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsMergePrefs) {
// Write a bunch of data files in order to increase the chance to detect the
// provider not respecting lexicographic ordering when reading them. Since the
// filesystem may return files in arbitrary order, there is no way to be sure,
// but this is better than nothing.
base::DictionaryValue test_dict_bar;
test_dict_bar.SetString("HomepageLocation", "http://bar.com");
for (unsigned int i = 1; i <= 4; ++i)
harness_.WriteConfigFile(test_dict_bar, base::UintToString(i));
base::DictionaryValue test_dict_foo;
test_dict_foo.SetString("HomepageLocation", "http://foo.com");
harness_.WriteConfigFile(test_dict_foo, "9");
for (unsigned int i = 5; i <= 8; ++i)
harness_.WriteConfigFile(test_dict_bar, base::UintToString(i));
ConfigDirPolicyLoader loader(loop_.task_runner(), harness_.test_dir(),
POLICY_SCOPE_USER);
std::unique_ptr<PolicyBundle> bundle(loader.Load());
ASSERT_TRUE(bundle.get());
PolicyBundle expected_bundle;
expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.LoadFrom(&test_dict_foo, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM);
EXPECT_TRUE(bundle->Equals(expected_bundle));
}
} // namespace policy