1 // Copyright (c) 2012 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 "base/compiler_specific.h"
6 #include "base/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/json/json_string_value_serializer.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "components/policy/core/common/async_policy_provider.h"
16 #include "components/policy/core/common/config_dir_policy_loader.h"
17 #include "components/policy/core/common/configuration_policy_provider_test.h"
18 #include "components/policy/core/common/policy_bundle.h"
19 #include "components/policy/core/common/policy_map.h"
20
21 namespace policy {
22
23 namespace {
24
25 // Subdirectory of the config dir that contains mandatory policies.
26 const base::FilePath::CharType kMandatoryPath[] = FILE_PATH_LITERAL("managed");
27
28 class TestHarness : public PolicyProviderTestHarness {
29 public:
30 TestHarness();
31 virtual ~TestHarness();
32
33 virtual void SetUp() OVERRIDE;
34
35 virtual ConfigurationPolicyProvider* CreateProvider(
36 SchemaRegistry* registry,
37 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
38
39 virtual void InstallEmptyPolicy() OVERRIDE;
40 virtual void InstallStringPolicy(const std::string& policy_name,
41 const std::string& policy_value) OVERRIDE;
42 virtual void InstallIntegerPolicy(const std::string& policy_name,
43 int policy_value) OVERRIDE;
44 virtual void InstallBooleanPolicy(const std::string& policy_name,
45 bool policy_value) OVERRIDE;
46 virtual void InstallStringListPolicy(
47 const std::string& policy_name,
48 const base::ListValue* policy_value) OVERRIDE;
49 virtual void InstallDictionaryPolicy(
50 const std::string& policy_name,
51 const base::DictionaryValue* policy_value) OVERRIDE;
52 virtual void Install3rdPartyPolicy(
53 const base::DictionaryValue* policies) OVERRIDE;
54
test_dir()55 const base::FilePath& test_dir() { return test_dir_.path(); }
56
57 // JSON-encode a dictionary and write it to a file.
58 void WriteConfigFile(const base::DictionaryValue& dict,
59 const std::string& file_name);
60
61 // Returns a unique name for a policy file. Each subsequent call returns a new
62 // name that comes lexicographically after the previous one.
63 std::string NextConfigFileName();
64
65 static PolicyProviderTestHarness* Create();
66
67 private:
68 base::ScopedTempDir test_dir_;
69 int next_policy_file_index_;
70
71 DISALLOW_COPY_AND_ASSIGN(TestHarness);
72 };
73
TestHarness()74 TestHarness::TestHarness()
75 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE),
76 next_policy_file_index_(100) {}
77
~TestHarness()78 TestHarness::~TestHarness() {}
79
SetUp()80 void TestHarness::SetUp() {
81 ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
82 }
83
CreateProvider(SchemaRegistry * registry,scoped_refptr<base::SequencedTaskRunner> task_runner)84 ConfigurationPolicyProvider* TestHarness::CreateProvider(
85 SchemaRegistry* registry,
86 scoped_refptr<base::SequencedTaskRunner> task_runner) {
87 scoped_ptr<AsyncPolicyLoader> loader(new ConfigDirPolicyLoader(
88 task_runner, test_dir(), POLICY_SCOPE_MACHINE));
89 return new AsyncPolicyProvider(registry, loader.Pass());
90 }
91
InstallEmptyPolicy()92 void TestHarness::InstallEmptyPolicy() {
93 base::DictionaryValue dict;
94 WriteConfigFile(dict, NextConfigFileName());
95 }
96
InstallStringPolicy(const std::string & policy_name,const std::string & policy_value)97 void TestHarness::InstallStringPolicy(const std::string& policy_name,
98 const std::string& policy_value) {
99 base::DictionaryValue dict;
100 dict.SetString(policy_name, policy_value);
101 WriteConfigFile(dict, NextConfigFileName());
102 }
103
InstallIntegerPolicy(const std::string & policy_name,int policy_value)104 void TestHarness::InstallIntegerPolicy(const std::string& policy_name,
105 int policy_value) {
106 base::DictionaryValue dict;
107 dict.SetInteger(policy_name, policy_value);
108 WriteConfigFile(dict, NextConfigFileName());
109 }
110
InstallBooleanPolicy(const std::string & policy_name,bool policy_value)111 void TestHarness::InstallBooleanPolicy(const std::string& policy_name,
112 bool policy_value) {
113 base::DictionaryValue dict;
114 dict.SetBoolean(policy_name, policy_value);
115 WriteConfigFile(dict, NextConfigFileName());
116 }
117
InstallStringListPolicy(const std::string & policy_name,const base::ListValue * policy_value)118 void TestHarness::InstallStringListPolicy(const std::string& policy_name,
119 const base::ListValue* policy_value) {
120 base::DictionaryValue dict;
121 dict.Set(policy_name, policy_value->DeepCopy());
122 WriteConfigFile(dict, NextConfigFileName());
123 }
124
InstallDictionaryPolicy(const std::string & policy_name,const base::DictionaryValue * policy_value)125 void TestHarness::InstallDictionaryPolicy(
126 const std::string& policy_name,
127 const base::DictionaryValue* policy_value) {
128 base::DictionaryValue dict;
129 dict.Set(policy_name, policy_value->DeepCopy());
130 WriteConfigFile(dict, NextConfigFileName());
131 }
132
Install3rdPartyPolicy(const base::DictionaryValue * policies)133 void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) {
134 base::DictionaryValue dict;
135 dict.Set("3rdparty", policies->DeepCopy());
136 WriteConfigFile(dict, NextConfigFileName());
137 }
138
WriteConfigFile(const base::DictionaryValue & dict,const std::string & file_name)139 void TestHarness::WriteConfigFile(const base::DictionaryValue& dict,
140 const std::string& file_name) {
141 std::string data;
142 JSONStringValueSerializer serializer(&data);
143 serializer.Serialize(dict);
144 const base::FilePath mandatory_dir(test_dir().Append(kMandatoryPath));
145 ASSERT_TRUE(base::CreateDirectory(mandatory_dir));
146 const base::FilePath file_path(mandatory_dir.AppendASCII(file_name));
147 ASSERT_EQ((int) data.size(),
148 base::WriteFile(file_path, data.c_str(), data.size()));
149 }
150
NextConfigFileName()151 std::string TestHarness::NextConfigFileName() {
152 EXPECT_LE(next_policy_file_index_, 999);
153 return std::string("policy") + base::IntToString(next_policy_file_index_++);
154 }
155
156 // static
Create()157 PolicyProviderTestHarness* TestHarness::Create() {
158 return new TestHarness();
159 }
160
161 } // namespace
162
163 // Instantiate abstract test case for basic policy reading tests.
164 INSTANTIATE_TEST_CASE_P(
165 ConfigDirPolicyLoaderTest,
166 ConfigurationPolicyProviderTest,
167 testing::Values(TestHarness::Create));
168
169 // Instantiate abstract test case for 3rd party policy reading tests.
170 INSTANTIATE_TEST_CASE_P(
171 ConfigDir3rdPartyPolicyLoaderTest,
172 Configuration3rdPartyPolicyProviderTest,
173 testing::Values(TestHarness::Create));
174
175 // Some tests that exercise special functionality in ConfigDirPolicyLoader.
176 class ConfigDirPolicyLoaderTest : public PolicyTestBase {
177 protected:
SetUp()178 virtual void SetUp() OVERRIDE {
179 PolicyTestBase::SetUp();
180 harness_.SetUp();
181 }
182
183 TestHarness harness_;
184 };
185
186 // The preferences dictionary is expected to be empty when there are no files to
187 // load.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsEmpty)188 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
189 ConfigDirPolicyLoader loader(
190 loop_.message_loop_proxy(), harness_.test_dir(), POLICY_SCOPE_MACHINE);
191 scoped_ptr<PolicyBundle> bundle(loader.Load());
192 ASSERT_TRUE(bundle.get());
193 const PolicyBundle kEmptyBundle;
194 EXPECT_TRUE(bundle->Equals(kEmptyBundle));
195 }
196
197 // Reading from a non-existent directory should result in an empty preferences
198 // dictionary.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsNonExistentDirectory)199 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) {
200 base::FilePath non_existent_dir(
201 harness_.test_dir().Append(FILE_PATH_LITERAL("not_there")));
202 ConfigDirPolicyLoader loader(
203 loop_.message_loop_proxy(), non_existent_dir, POLICY_SCOPE_MACHINE);
204 scoped_ptr<PolicyBundle> bundle(loader.Load());
205 ASSERT_TRUE(bundle.get());
206 const PolicyBundle kEmptyBundle;
207 EXPECT_TRUE(bundle->Equals(kEmptyBundle));
208 }
209
210 // Test merging values from different files.
TEST_F(ConfigDirPolicyLoaderTest,ReadPrefsMergePrefs)211 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsMergePrefs) {
212 // Write a bunch of data files in order to increase the chance to detect the
213 // provider not respecting lexicographic ordering when reading them. Since the
214 // filesystem may return files in arbitrary order, there is no way to be sure,
215 // but this is better than nothing.
216 base::DictionaryValue test_dict_bar;
217 test_dict_bar.SetString("HomepageLocation", "http://bar.com");
218 for (unsigned int i = 1; i <= 4; ++i)
219 harness_.WriteConfigFile(test_dict_bar, base::IntToString(i));
220 base::DictionaryValue test_dict_foo;
221 test_dict_foo.SetString("HomepageLocation", "http://foo.com");
222 harness_.WriteConfigFile(test_dict_foo, "9");
223 for (unsigned int i = 5; i <= 8; ++i)
224 harness_.WriteConfigFile(test_dict_bar, base::IntToString(i));
225
226 ConfigDirPolicyLoader loader(
227 loop_.message_loop_proxy(), harness_.test_dir(), POLICY_SCOPE_USER);
228 scoped_ptr<PolicyBundle> bundle(loader.Load());
229 ASSERT_TRUE(bundle.get());
230 PolicyBundle expected_bundle;
231 expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
232 .LoadFrom(&test_dict_foo, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
233 EXPECT_TRUE(bundle->Equals(expected_bundle));
234 }
235
236 } // namespace policy
237