Add base:: to string16 components/.
[chromium-blink-merge.git] / components / policy / core / common / policy_loader_win_unittest.cc
blob46f61331da689c8887d5a2b5bc604fb7cc925919
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.
5 #include "components/policy/core/common/policy_loader_win.h"
7 #include <windows.h>
8 #include <userenv.h>
10 #include <algorithm>
11 #include <cstring>
12 #include <functional>
13 #include <iterator>
14 #include <vector>
16 #include "base/base_paths.h"
17 #include "base/callback.h"
18 #include "base/file_util.h"
19 #include "base/files/file_path.h"
20 #include "base/files/scoped_temp_dir.h"
21 #include "base/json/json_writer.h"
22 #include "base/path_service.h"
23 #include "base/process/process.h"
24 #include "base/strings/string16.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/sys_byteorder.h"
30 #include "base/win/registry.h"
31 #include "components/policy/core/common/async_policy_provider.h"
32 #include "components/policy/core/common/configuration_policy_provider_test.h"
33 #include "components/policy/core/common/external_data_fetcher.h"
34 #include "components/policy/core/common/policy_bundle.h"
35 #include "components/policy/core/common/policy_map.h"
36 #include "components/policy/core/common/preg_parser_win.h"
37 #include "components/policy/core/common/schema_map.h"
38 #include "testing/gtest/include/gtest/gtest.h"
40 using base::win::RegKey;
42 namespace policy {
44 namespace {
46 // Constants for registry key names.
47 const wchar_t kPathSep[] = L"\\";
48 const wchar_t kThirdParty[] = L"3rdparty";
49 const wchar_t kMandatory[] = L"policy";
50 const wchar_t kRecommended[] = L"recommended";
51 const char kSchema[] = "schema";
52 const wchar_t kTestPolicyKey[] = L"chrome.policy.key";
54 // Installs |value| in the given registry |path| and |hive|, under the key
55 // |name|. Returns false on errors.
56 // Some of the possible Value types are stored after a conversion (e.g. doubles
57 // are stored as strings), and can only be retrieved if a corresponding schema
58 // is written.
59 bool InstallValue(const base::Value& value,
60 HKEY hive,
61 const base::string16& path,
62 const base::string16& name) {
63 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet.
64 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS);
65 EXPECT_TRUE(key.Valid());
66 switch (value.GetType()) {
67 case base::Value::TYPE_NULL:
68 return key.WriteValue(name.c_str(), L"") == ERROR_SUCCESS;
70 case base::Value::TYPE_BOOLEAN: {
71 bool bool_value;
72 if (!value.GetAsBoolean(&bool_value))
73 return false;
74 return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS;
77 case base::Value::TYPE_INTEGER: {
78 int int_value;
79 if (!value.GetAsInteger(&int_value))
80 return false;
81 return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS;
84 case base::Value::TYPE_DOUBLE: {
85 double double_value;
86 if (!value.GetAsDouble(&double_value))
87 return false;
88 base::string16 str_value =
89 UTF8ToUTF16(base::DoubleToString(double_value));
90 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
93 case base::Value::TYPE_STRING: {
94 base::string16 str_value;
95 if (!value.GetAsString(&str_value))
96 return false;
97 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
100 case base::Value::TYPE_DICTIONARY: {
101 const base::DictionaryValue* sub_dict = NULL;
102 if (!value.GetAsDictionary(&sub_dict))
103 return false;
104 for (base::DictionaryValue::Iterator it(*sub_dict);
105 !it.IsAtEnd(); it.Advance()) {
106 if (!InstallValue(it.value(), hive, path + kPathSep + name,
107 UTF8ToUTF16(it.key()))) {
108 return false;
111 return true;
114 case base::Value::TYPE_LIST: {
115 const base::ListValue* list = NULL;
116 if (!value.GetAsList(&list))
117 return false;
118 for (size_t i = 0; i < list->GetSize(); ++i) {
119 const base::Value* item;
120 if (!list->Get(i, &item))
121 return false;
122 if (!InstallValue(*item, hive, path + kPathSep + name,
123 base::UintToString16(i + 1))) {
124 return false;
127 return true;
130 case base::Value::TYPE_BINARY:
131 return false;
133 NOTREACHED();
134 return false;
137 // This class provides sandboxing and mocking for the parts of the Windows
138 // Registry implementing Group Policy. It prepares two temporary sandbox keys,
139 // one for HKLM and one for HKCU. A test's calls to the registry are redirected
140 // by Windows to these sandboxes, allowing the tests to manipulate and access
141 // policy as if it were active, but without actually changing the parts of the
142 // Registry that are managed by Group Policy.
143 class ScopedGroupPolicyRegistrySandbox {
144 public:
145 ScopedGroupPolicyRegistrySandbox();
146 ~ScopedGroupPolicyRegistrySandbox();
148 private:
149 void ActivateOverrides();
150 void RemoveOverrides();
152 // Deletes the sandbox keys.
153 void DeleteKeys();
155 std::wstring key_name_;
157 // Keys are created for the lifetime of a test to contain
158 // the sandboxed HKCU and HKLM hives, respectively.
159 RegKey temp_hkcu_hive_key_;
160 RegKey temp_hklm_hive_key_;
162 DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox);
165 // A test harness that feeds policy via the Chrome GPO registry subtree.
166 class RegistryTestHarness : public PolicyProviderTestHarness,
167 public AppliedGPOListProvider {
168 public:
169 RegistryTestHarness(HKEY hive, PolicyScope scope);
170 virtual ~RegistryTestHarness();
172 // PolicyProviderTestHarness:
173 virtual void SetUp() OVERRIDE;
175 virtual ConfigurationPolicyProvider* CreateProvider(
176 SchemaRegistry* registry,
177 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
179 virtual void InstallEmptyPolicy() OVERRIDE;
180 virtual void InstallStringPolicy(const std::string& policy_name,
181 const std::string& policy_value) OVERRIDE;
182 virtual void InstallIntegerPolicy(const std::string& policy_name,
183 int policy_value) OVERRIDE;
184 virtual void InstallBooleanPolicy(const std::string& policy_name,
185 bool policy_value) OVERRIDE;
186 virtual void InstallStringListPolicy(
187 const std::string& policy_name,
188 const base::ListValue* policy_value) OVERRIDE;
189 virtual void InstallDictionaryPolicy(
190 const std::string& policy_name,
191 const base::DictionaryValue* policy_value) OVERRIDE;
192 virtual void Install3rdPartyPolicy(
193 const base::DictionaryValue* policies) OVERRIDE;
195 // AppliedGPOListProvider:
196 virtual DWORD GetAppliedGPOList(DWORD flags,
197 LPCTSTR machine_name,
198 PSID sid_user,
199 GUID* extension_guid,
200 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
201 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
203 // Creates a harness instance that will install policy in HKCU or HKLM,
204 // respectively.
205 static PolicyProviderTestHarness* CreateHKCU();
206 static PolicyProviderTestHarness* CreateHKLM();
208 private:
209 HKEY hive_;
211 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
213 DISALLOW_COPY_AND_ASSIGN(RegistryTestHarness);
216 // A test harness that generates PReg files for the provider to read.
217 class PRegTestHarness : public PolicyProviderTestHarness,
218 public AppliedGPOListProvider {
219 public:
220 PRegTestHarness();
221 virtual ~PRegTestHarness();
223 // PolicyProviderTestHarness:
224 virtual void SetUp() OVERRIDE;
226 virtual ConfigurationPolicyProvider* CreateProvider(
227 SchemaRegistry* registry,
228 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
230 virtual void InstallEmptyPolicy() OVERRIDE;
231 virtual void InstallStringPolicy(const std::string& policy_name,
232 const std::string& policy_value) OVERRIDE;
233 virtual void InstallIntegerPolicy(const std::string& policy_name,
234 int policy_value) OVERRIDE;
235 virtual void InstallBooleanPolicy(const std::string& policy_name,
236 bool policy_value) OVERRIDE;
237 virtual void InstallStringListPolicy(
238 const std::string& policy_name,
239 const base::ListValue* policy_value) OVERRIDE;
240 virtual void InstallDictionaryPolicy(
241 const std::string& policy_name,
242 const base::DictionaryValue* policy_value) OVERRIDE;
243 virtual void Install3rdPartyPolicy(
244 const base::DictionaryValue* policies) OVERRIDE;
246 // AppliedGPOListProvider:
247 virtual DWORD GetAppliedGPOList(DWORD flags,
248 LPCTSTR machine_name,
249 PSID sid_user,
250 GUID* extension_guid,
251 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
252 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
254 // Creates a harness instance.
255 static PolicyProviderTestHarness* Create();
257 private:
258 // Helper to append a base::string16 to an uint8 buffer.
259 static void AppendChars(std::vector<uint8>* buffer,
260 const base::string16& chars);
262 // Appends a record with the given fields to the PReg file.
263 void AppendRecordToPRegFile(const base::string16& path,
264 const std::string& key,
265 DWORD type,
266 DWORD size,
267 uint8* data);
269 // Appends the given DWORD |value| for |path| + |key| to the PReg file.
270 void AppendDWORDToPRegFile(const base::string16& path,
271 const std::string& key,
272 DWORD value);
274 // Appends the given string |value| for |path| + |key| to the PReg file.
275 void AppendStringToPRegFile(const base::string16& path,
276 const std::string& key,
277 const std::string& value);
279 // Appends the given policy |value| for |path| + |key| to the PReg file,
280 // converting and recursing as necessary.
281 void AppendPolicyToPRegFile(const base::string16& path,
282 const std::string& key,
283 const base::Value* value);
285 base::ScopedTempDir temp_dir_;
286 base::FilePath preg_file_path_;
287 GROUP_POLICY_OBJECT gpo_;
289 DISALLOW_COPY_AND_ASSIGN(PRegTestHarness);
292 ScopedGroupPolicyRegistrySandbox::ScopedGroupPolicyRegistrySandbox() {
293 // Generate a unique registry key for the override for each test. This
294 // makes sure that tests executing in parallel won't delete each other's
295 // key, at DeleteKeys().
296 key_name_ = ASCIIToWide(base::StringPrintf(
297 "SOFTWARE\\chromium unittest %d",
298 base::Process::Current().pid()));
299 std::wstring hklm_key_name = key_name_ + L"\\HKLM";
300 std::wstring hkcu_key_name = key_name_ + L"\\HKCU";
302 // Create the subkeys to hold the overridden HKLM and HKCU
303 // policy settings.
304 temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
305 hklm_key_name.c_str(),
306 KEY_ALL_ACCESS);
307 temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
308 hkcu_key_name.c_str(),
309 KEY_ALL_ACCESS);
311 ActivateOverrides();
314 ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() {
315 RemoveOverrides();
316 DeleteKeys();
319 void ScopedGroupPolicyRegistrySandbox::ActivateOverrides() {
320 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE,
321 temp_hklm_hive_key_.Handle()));
322 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER,
323 temp_hkcu_hive_key_.Handle()));
326 void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() {
327 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0));
328 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0));
331 void ScopedGroupPolicyRegistrySandbox::DeleteKeys() {
332 RegKey key(HKEY_CURRENT_USER, key_name_.c_str(), KEY_ALL_ACCESS);
333 ASSERT_TRUE(key.Valid());
334 key.DeleteKey(L"");
337 RegistryTestHarness::RegistryTestHarness(HKEY hive, PolicyScope scope)
338 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {}
340 RegistryTestHarness::~RegistryTestHarness() {}
342 void RegistryTestHarness::SetUp() {}
344 ConfigurationPolicyProvider* RegistryTestHarness::CreateProvider(
345 SchemaRegistry* registry,
346 scoped_refptr<base::SequencedTaskRunner> task_runner) {
347 scoped_ptr<AsyncPolicyLoader> loader(
348 new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
349 return new AsyncPolicyProvider(registry, loader.Pass());
352 void RegistryTestHarness::InstallEmptyPolicy() {}
354 void RegistryTestHarness::InstallStringPolicy(
355 const std::string& policy_name,
356 const std::string& policy_value) {
357 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
358 ASSERT_TRUE(key.Valid());
359 ASSERT_HRESULT_SUCCEEDED(key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
360 UTF8ToUTF16(policy_value).c_str()));
363 void RegistryTestHarness::InstallIntegerPolicy(
364 const std::string& policy_name,
365 int policy_value) {
366 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
367 ASSERT_TRUE(key.Valid());
368 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
369 static_cast<DWORD>(policy_value));
372 void RegistryTestHarness::InstallBooleanPolicy(
373 const std::string& policy_name,
374 bool policy_value) {
375 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
376 ASSERT_TRUE(key.Valid());
377 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
378 static_cast<DWORD>(policy_value));
381 void RegistryTestHarness::InstallStringListPolicy(
382 const std::string& policy_name,
383 const base::ListValue* policy_value) {
384 RegKey key(hive_,
385 (base::string16(kTestPolicyKey) + ASCIIToUTF16("\\") +
386 UTF8ToUTF16(policy_name)).c_str(),
387 KEY_ALL_ACCESS);
388 ASSERT_TRUE(key.Valid());
389 int index = 1;
390 for (base::ListValue::const_iterator element(policy_value->begin());
391 element != policy_value->end();
392 ++element) {
393 std::string element_value;
394 if (!(*element)->GetAsString(&element_value))
395 continue;
396 std::string name(base::IntToString(index++));
397 key.WriteValue(UTF8ToUTF16(name).c_str(),
398 UTF8ToUTF16(element_value).c_str());
402 void RegistryTestHarness::InstallDictionaryPolicy(
403 const std::string& policy_name,
404 const base::DictionaryValue* policy_value) {
405 std::string json;
406 base::JSONWriter::Write(policy_value, &json);
407 RegKey key(hive_, kTestPolicyKey, KEY_ALL_ACCESS);
408 ASSERT_TRUE(key.Valid());
409 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
410 UTF8ToUTF16(json).c_str());
413 void RegistryTestHarness::Install3rdPartyPolicy(
414 const base::DictionaryValue* policies) {
415 // The first level entries are domains, and the second level entries map
416 // components to their policy.
417 const base::string16 kPathPrefix =
418 base::string16(kTestPolicyKey) + kPathSep + kThirdParty + kPathSep;
419 for (base::DictionaryValue::Iterator domain(*policies);
420 !domain.IsAtEnd(); domain.Advance()) {
421 const base::DictionaryValue* components = NULL;
422 if (!domain.value().GetAsDictionary(&components)) {
423 ADD_FAILURE();
424 continue;
426 for (base::DictionaryValue::Iterator component(*components);
427 !component.IsAtEnd(); component.Advance()) {
428 const base::string16 path = kPathPrefix +
429 UTF8ToUTF16(domain.key()) + kPathSep + UTF8ToUTF16(component.key());
430 InstallValue(component.value(), hive_, path, kMandatory);
435 DWORD RegistryTestHarness::GetAppliedGPOList(DWORD flags,
436 LPCTSTR machine_name,
437 PSID sid_user,
438 GUID* extension_guid,
439 PGROUP_POLICY_OBJECT* gpo_list) {
440 *gpo_list = NULL;
441 return ERROR_ACCESS_DENIED;
444 BOOL RegistryTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
445 return TRUE;
448 // static
449 PolicyProviderTestHarness* RegistryTestHarness::CreateHKCU() {
450 return new RegistryTestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER);
453 // static
454 PolicyProviderTestHarness* RegistryTestHarness::CreateHKLM() {
455 return new RegistryTestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE);
458 PRegTestHarness::PRegTestHarness()
459 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE) {}
461 PRegTestHarness::~PRegTestHarness() {}
463 void PRegTestHarness::SetUp() {
464 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
465 preg_file_path_ = temp_dir_.path().Append(PolicyLoaderWin::kPRegFileName);
466 ASSERT_TRUE(file_util::WriteFile(preg_file_path_,
467 preg_parser::kPRegFileHeader,
468 arraysize(preg_parser::kPRegFileHeader)));
470 memset(&gpo_, 0, sizeof(GROUP_POLICY_OBJECT));
471 gpo_.lpFileSysPath = const_cast<wchar_t*>(temp_dir_.path().value().c_str());
474 ConfigurationPolicyProvider* PRegTestHarness::CreateProvider(
475 SchemaRegistry* registry,
476 scoped_refptr<base::SequencedTaskRunner> task_runner) {
477 scoped_ptr<AsyncPolicyLoader> loader(
478 new PolicyLoaderWin(task_runner, kTestPolicyKey, this));
479 return new AsyncPolicyProvider(registry, loader.Pass());
482 void PRegTestHarness::InstallEmptyPolicy() {}
484 void PRegTestHarness::InstallStringPolicy(const std::string& policy_name,
485 const std::string& policy_value) {
486 AppendStringToPRegFile(kTestPolicyKey, policy_name, policy_value);
489 void PRegTestHarness::InstallIntegerPolicy(const std::string& policy_name,
490 int policy_value) {
491 AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
494 void PRegTestHarness::InstallBooleanPolicy(const std::string& policy_name,
495 bool policy_value) {
496 AppendDWORDToPRegFile(kTestPolicyKey, policy_name, policy_value);
499 void PRegTestHarness::InstallStringListPolicy(
500 const std::string& policy_name,
501 const base::ListValue* policy_value) {
502 AppendPolicyToPRegFile(kTestPolicyKey, policy_name, policy_value);
505 void PRegTestHarness::InstallDictionaryPolicy(
506 const std::string& policy_name,
507 const base::DictionaryValue* policy_value) {
508 std::string json;
509 base::JSONWriter::Write(policy_value, &json);
510 AppendStringToPRegFile(kTestPolicyKey, policy_name, json);
513 void PRegTestHarness::Install3rdPartyPolicy(
514 const base::DictionaryValue* policies) {
515 // The first level entries are domains, and the second level entries map
516 // components to their policy.
517 const base::string16 kPathPrefix =
518 base::string16(kTestPolicyKey) + kPathSep + kThirdParty + kPathSep;
519 for (base::DictionaryValue::Iterator domain(*policies);
520 !domain.IsAtEnd(); domain.Advance()) {
521 const base::DictionaryValue* components = NULL;
522 if (!domain.value().GetAsDictionary(&components)) {
523 ADD_FAILURE();
524 continue;
526 const base::string16 domain_path = kPathPrefix + UTF8ToUTF16(domain.key());
527 for (base::DictionaryValue::Iterator component(*components);
528 !component.IsAtEnd(); component.Advance()) {
529 const base::string16 component_path =
530 domain_path + kPathSep + UTF8ToUTF16(component.key());
531 AppendPolicyToPRegFile(component_path, UTF16ToUTF8(kMandatory),
532 &component.value());
537 DWORD PRegTestHarness::GetAppliedGPOList(DWORD flags,
538 LPCTSTR machine_name,
539 PSID sid_user,
540 GUID* extension_guid,
541 PGROUP_POLICY_OBJECT* gpo_list) {
542 *gpo_list = flags & GPO_LIST_FLAG_MACHINE ? &gpo_ : NULL;
543 return ERROR_SUCCESS;
546 BOOL PRegTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
547 return TRUE;
550 // static
551 PolicyProviderTestHarness* PRegTestHarness::Create() {
552 return new PRegTestHarness();
555 // static
556 void PRegTestHarness::AppendChars(std::vector<uint8>* buffer,
557 const base::string16& chars) {
558 for (base::string16::const_iterator c(chars.begin()); c != chars.end(); ++c) {
559 buffer->push_back(*c & 0xff);
560 buffer->push_back((*c >> 8) & 0xff);
564 void PRegTestHarness::AppendRecordToPRegFile(const base::string16& path,
565 const std::string& key,
566 DWORD type,
567 DWORD size,
568 uint8* data) {
569 std::vector<uint8> buffer;
570 AppendChars(&buffer, L"[");
571 AppendChars(&buffer, path);
572 AppendChars(&buffer, base::string16(L"\0;", 2));
573 AppendChars(&buffer, UTF8ToUTF16(key));
574 AppendChars(&buffer, base::string16(L"\0;", 2));
575 type = base::ByteSwapToLE32(type);
576 uint8* type_data = reinterpret_cast<uint8*>(&type);
577 buffer.insert(buffer.end(), type_data, type_data + sizeof(DWORD));
578 AppendChars(&buffer, L";");
579 size = base::ByteSwapToLE32(size);
580 uint8* size_data = reinterpret_cast<uint8*>(&size);
581 buffer.insert(buffer.end(), size_data, size_data + sizeof(DWORD));
582 AppendChars(&buffer, L";");
583 buffer.insert(buffer.end(), data, data + size);
584 AppendChars(&buffer, L"]");
586 ASSERT_EQ(buffer.size(),
587 file_util::AppendToFile(
588 preg_file_path_,
589 reinterpret_cast<const char*>(vector_as_array(&buffer)),
590 buffer.size()));
593 void PRegTestHarness::AppendDWORDToPRegFile(const base::string16& path,
594 const std::string& key,
595 DWORD value) {
596 value = base::ByteSwapToLE32(value);
597 AppendRecordToPRegFile(path, key, REG_DWORD, sizeof(DWORD),
598 reinterpret_cast<uint8*>(&value));
601 void PRegTestHarness::AppendStringToPRegFile(const base::string16& path,
602 const std::string& key,
603 const std::string& value) {
604 base::string16 string16_value(UTF8ToUTF16(value));
605 std::vector<char16> data;
606 std::transform(string16_value.begin(), string16_value.end(),
607 std::back_inserter(data), std::ptr_fun(base::ByteSwapToLE16));
608 data.push_back(base::ByteSwapToLE16(L'\0'));
610 AppendRecordToPRegFile(path, key, REG_SZ, data.size() * sizeof(char16),
611 reinterpret_cast<uint8*>(vector_as_array(&data)));
614 void PRegTestHarness::AppendPolicyToPRegFile(const base::string16& path,
615 const std::string& key,
616 const base::Value* value) {
617 switch (value->GetType()) {
618 case base::Value::TYPE_BOOLEAN: {
619 bool boolean_value = false;
620 ASSERT_TRUE(value->GetAsBoolean(&boolean_value));
621 AppendDWORDToPRegFile(path, key, boolean_value);
622 break;
624 case base::Value::TYPE_INTEGER: {
625 int int_value = 0;
626 ASSERT_TRUE(value->GetAsInteger(&int_value));
627 AppendDWORDToPRegFile(path, key, int_value);
628 break;
630 case base::Value::TYPE_DOUBLE: {
631 double double_value = 0;
632 ASSERT_TRUE(value->GetAsDouble(&double_value));
633 AppendStringToPRegFile(path, key, base::DoubleToString(double_value));
634 break;
636 case base::Value::TYPE_STRING: {
637 std::string string_value;
638 ASSERT_TRUE(value->GetAsString(&string_value));
639 AppendStringToPRegFile(path, key, string_value);
640 break;
642 case base::Value::TYPE_DICTIONARY: {
643 base::string16 subpath = path + kPathSep + UTF8ToUTF16(key);
644 const base::DictionaryValue* dict = NULL;
645 ASSERT_TRUE(value->GetAsDictionary(&dict));
646 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
647 entry.Advance()) {
648 AppendPolicyToPRegFile(subpath, entry.key(), &entry.value());
650 break;
652 case base::Value::TYPE_LIST: {
653 base::string16 subpath = path + kPathSep + UTF8ToUTF16(key);
654 const base::ListValue* list = NULL;
655 ASSERT_TRUE(value->GetAsList(&list));
656 for (size_t i = 0; i < list->GetSize(); ++i) {
657 const base::Value* entry = NULL;
658 ASSERT_TRUE(list->Get(i, &entry));
659 AppendPolicyToPRegFile(subpath, base::IntToString(i + 1), entry);
661 break;
663 case base::Value::TYPE_BINARY:
664 case base::Value::TYPE_NULL: {
665 ADD_FAILURE();
666 break;
671 } // namespace
673 // Instantiate abstract test case for basic policy reading tests.
674 INSTANTIATE_TEST_CASE_P(
675 PolicyProviderWinTest,
676 ConfigurationPolicyProviderTest,
677 testing::Values(RegistryTestHarness::CreateHKCU,
678 RegistryTestHarness::CreateHKLM,
679 PRegTestHarness::Create));
681 // Instantiate abstract test case for 3rd party policy reading tests.
682 INSTANTIATE_TEST_CASE_P(
683 ThirdPartyPolicyProviderWinTest,
684 Configuration3rdPartyPolicyProviderTest,
685 testing::Values(RegistryTestHarness::CreateHKCU,
686 RegistryTestHarness::CreateHKLM,
687 PRegTestHarness::Create));
689 // Test cases for windows policy provider specific functionality.
690 class PolicyLoaderWinTest : public PolicyTestBase,
691 public AppliedGPOListProvider {
692 protected:
693 // The policy key this tests places data under. This must match the data
694 // files in chrome/test/data/policy/gpo.
695 static const char16 kTestPolicyKey[];
697 PolicyLoaderWinTest()
698 : gpo_list_(NULL),
699 gpo_list_status_(ERROR_ACCESS_DENIED) {}
700 virtual ~PolicyLoaderWinTest() {}
702 virtual void SetUp() OVERRIDE {
703 PolicyTestBase::SetUp();
705 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
706 test_data_dir_ = test_data_dir_.AppendASCII("chrome")
707 .AppendASCII("test")
708 .AppendASCII("data")
709 .AppendASCII("policy")
710 .AppendASCII("gpo");
713 // AppliedGPOListProvider:
714 virtual DWORD GetAppliedGPOList(DWORD flags,
715 LPCTSTR machine_name,
716 PSID sid_user,
717 GUID* extension_guid,
718 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
719 *gpo_list = gpo_list_;
720 return gpo_list_status_;
722 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
723 return TRUE;
726 void InitGPO(GROUP_POLICY_OBJECT* gpo,
727 DWORD options,
728 const base::FilePath& path,
729 GROUP_POLICY_OBJECT* next,
730 GROUP_POLICY_OBJECT* prev) {
731 memset(gpo, 0, sizeof(GROUP_POLICY_OBJECT));
732 gpo->dwOptions = options;
733 gpo->lpFileSysPath = const_cast<wchar_t*>(path.value().c_str());
734 gpo->pNext = next;
735 gpo->pPrev = prev;
738 bool Matches(const PolicyBundle& expected) {
739 PolicyLoaderWin loader(loop_.message_loop_proxy(), kTestPolicyKey, this);
740 scoped_ptr<PolicyBundle> loaded(
741 loader.InitialLoad(schema_registry_.schema_map()));
742 return loaded->Equals(expected);
745 void InstallRegistrySentinel() {
746 RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
747 ASSERT_TRUE(hklm_key.Valid());
748 hklm_key.WriteValue(
749 UTF8ToUTF16(test_keys::kKeyString).c_str(),
750 UTF8ToUTF16("registry").c_str());
753 bool MatchesRegistrySentinel() {
754 base::DictionaryValue expected_policy;
755 expected_policy.SetString(test_keys::kKeyString, "registry");
756 PolicyBundle expected;
757 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
758 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
759 return Matches(expected);
762 bool MatchesTestBundle() {
763 base::DictionaryValue expected_policy;
764 expected_policy.SetBoolean(test_keys::kKeyBoolean, true);
765 expected_policy.SetString(test_keys::kKeyString, "GPO");
766 expected_policy.SetInteger(test_keys::kKeyInteger, 42);
767 scoped_ptr<base::ListValue> list(new base::ListValue());
768 list->AppendString("GPO 1");
769 list->AppendString("GPO 2");
770 expected_policy.Set(test_keys::kKeyStringList, list.release());
771 PolicyBundle expected;
772 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
773 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY,
774 POLICY_SCOPE_MACHINE);
775 return Matches(expected);
778 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
779 PGROUP_POLICY_OBJECT gpo_list_;
780 DWORD gpo_list_status_;
781 base::FilePath test_data_dir_;
784 const char16 PolicyLoaderWinTest::kTestPolicyKey[] =
785 L"SOFTWARE\\Policies\\Chromium";
787 TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) {
788 RegKey hklm_key(HKEY_LOCAL_MACHINE, kTestPolicyKey, KEY_ALL_ACCESS);
789 ASSERT_TRUE(hklm_key.Valid());
790 hklm_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
791 UTF8ToUTF16("hklm").c_str());
792 RegKey hkcu_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
793 ASSERT_TRUE(hkcu_key.Valid());
794 hkcu_key.WriteValue(UTF8ToUTF16(test_keys::kKeyString).c_str(),
795 UTF8ToUTF16("hkcu").c_str());
797 PolicyBundle expected;
798 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
799 .Set(test_keys::kKeyString,
800 POLICY_LEVEL_MANDATORY,
801 POLICY_SCOPE_MACHINE,
802 base::Value::CreateStringValue("hklm"), NULL);
803 EXPECT_TRUE(Matches(expected));
806 TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
807 // Policy for the same extension will be provided at the 4 level/scope
808 // combinations, to verify that they overlap as expected.
809 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "merge");
810 ASSERT_TRUE(RegisterSchema(
813 " \"type\": \"object\","
814 " \"properties\": {"
815 " \"a\": { \"type\": \"string\" },"
816 " \"b\": { \"type\": \"string\" },"
817 " \"c\": { \"type\": \"string\" },"
818 " \"d\": { \"type\": \"string\" }"
819 " }"
820 "}"));
822 const base::string16 kPathSuffix =
823 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge");
825 const char kUserMandatory[] = "user-mandatory";
826 const char kUserRecommended[] = "user-recommended";
827 const char kMachineMandatory[] = "machine-mandatory";
828 const char kMachineRecommended[] = "machine-recommended";
830 base::DictionaryValue policy;
831 policy.SetString("a", kMachineMandatory);
832 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
833 kPathSuffix, kMandatory));
834 policy.SetString("a", kUserMandatory);
835 policy.SetString("b", kUserMandatory);
836 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
837 kPathSuffix, kMandatory));
838 policy.SetString("a", kMachineRecommended);
839 policy.SetString("b", kMachineRecommended);
840 policy.SetString("c", kMachineRecommended);
841 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
842 kPathSuffix, kRecommended));
843 policy.SetString("a", kUserRecommended);
844 policy.SetString("b", kUserRecommended);
845 policy.SetString("c", kUserRecommended);
846 policy.SetString("d", kUserRecommended);
847 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
848 kPathSuffix, kRecommended));
850 PolicyBundle expected;
851 PolicyMap& expected_policy = expected.Get(ns);
852 expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
853 base::Value::CreateStringValue(kMachineMandatory), NULL);
854 expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
855 base::Value::CreateStringValue(kUserMandatory), NULL);
856 expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
857 base::Value::CreateStringValue(kMachineRecommended),
858 NULL);
859 expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
860 base::Value::CreateStringValue(kUserRecommended), NULL);
861 EXPECT_TRUE(Matches(expected));
864 TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
865 // Create a dictionary with all the types that can be stored encoded in a
866 // string.
867 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "string");
868 ASSERT_TRUE(RegisterSchema(
871 " \"type\": \"object\","
872 " \"id\": \"MainType\","
873 " \"properties\": {"
874 " \"null\": { \"type\": \"null\" },"
875 " \"bool\": { \"type\": \"boolean\" },"
876 " \"int\": { \"type\": \"integer\" },"
877 " \"double\": { \"type\": \"number\" },"
878 " \"list\": {"
879 " \"type\": \"array\","
880 " \"items\": { \"$ref\": \"MainType\" }"
881 " },"
882 " \"dict\": { \"$ref\": \"MainType\" }"
883 " }"
884 "}"));
886 base::DictionaryValue policy;
887 policy.Set("null", base::Value::CreateNullValue());
888 policy.SetBoolean("bool", true);
889 policy.SetInteger("int", -123);
890 policy.SetDouble("double", 456.78e9);
891 base::ListValue list;
892 list.Append(policy.DeepCopy());
893 list.Append(policy.DeepCopy());
894 policy.Set("list", list.DeepCopy());
895 // Encode |policy| before adding the "dict" entry.
896 std::string encoded_dict;
897 base::JSONWriter::Write(&policy, &encoded_dict);
898 ASSERT_FALSE(encoded_dict.empty());
899 policy.Set("dict", policy.DeepCopy());
900 std::string encoded_list;
901 base::JSONWriter::Write(&list, &encoded_list);
902 ASSERT_FALSE(encoded_list.empty());
903 base::DictionaryValue encoded_policy;
904 encoded_policy.SetString("null", "");
905 encoded_policy.SetString("bool", "1");
906 encoded_policy.SetString("int", "-123");
907 encoded_policy.SetString("double", "456.78e9");
908 encoded_policy.SetString("list", encoded_list);
909 encoded_policy.SetString("dict", encoded_dict);
911 const base::string16 kPathSuffix =
912 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\string");
913 EXPECT_TRUE(
914 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
916 PolicyBundle expected;
917 expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
918 EXPECT_TRUE(Matches(expected));
921 TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
922 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "int");
923 ASSERT_TRUE(RegisterSchema(
926 " \"type\": \"object\","
927 " \"properties\": {"
928 " \"bool\": { \"type\": \"boolean\" },"
929 " \"int\": { \"type\": \"integer\" },"
930 " \"double\": { \"type\": \"number\" }"
931 " }"
932 "}"));
934 base::DictionaryValue encoded_policy;
935 encoded_policy.SetInteger("bool", 1);
936 encoded_policy.SetInteger("int", 123);
937 encoded_policy.SetInteger("double", 456);
939 const base::string16 kPathSuffix =
940 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\int");
941 EXPECT_TRUE(
942 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
944 base::DictionaryValue policy;
945 policy.SetBoolean("bool", true);
946 policy.SetInteger("int", 123);
947 policy.SetDouble("double", 456.0);
948 PolicyBundle expected;
949 expected.Get(ns).LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
950 EXPECT_TRUE(Matches(expected));
953 TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
954 // Build a schema for an "object" with a default schema for its properties.
955 // Note that the top-level object can't have "additionalProperties", so
956 // a "policy" property is used instead.
957 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, "test");
958 ASSERT_TRUE(RegisterSchema(
961 " \"type\": \"object\","
962 " \"properties\": {"
963 " \"policy\": {"
964 " \"type\": \"object\","
965 " \"properties\": {"
966 " \"special-int1\": { \"type\": \"integer\" },"
967 " \"special-int2\": { \"type\": \"integer\" }"
968 " },"
969 " \"additionalProperties\": { \"type\": \"number\" }"
970 " }"
971 " }"
972 "}"));
974 // Write some test values.
975 base::DictionaryValue policy;
976 // These special values have a specific schema for them.
977 policy.SetInteger("special-int1", 123);
978 policy.SetString("special-int2", "-456");
979 // Other values default to be loaded as doubles.
980 policy.SetInteger("double1", 789.0);
981 policy.SetString("double2", "123.456e7");
982 policy.SetString("invalid", "omg");
983 base::DictionaryValue all_policies;
984 all_policies.Set("policy", policy.DeepCopy());
986 const base::string16 kPathSuffix =
987 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\test");
988 EXPECT_TRUE(
989 InstallValue(all_policies, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
991 base::DictionaryValue expected_policy;
992 expected_policy.SetInteger("special-int1", 123);
993 expected_policy.SetInteger("special-int2", -456);
994 expected_policy.SetDouble("double1", 789.0);
995 expected_policy.SetDouble("double2", 123.456e7);
996 base::DictionaryValue expected_policies;
997 expected_policies.Set("policy", expected_policy.DeepCopy());
998 PolicyBundle expected;
999 expected.Get(ns).LoadFrom(
1000 &expected_policies, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1001 EXPECT_TRUE(Matches(expected));
1004 TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1005 InstallRegistrySentinel();
1006 gpo_list_ = NULL;
1007 gpo_list_status_ = ERROR_SUCCESS;
1009 PolicyBundle empty;
1010 EXPECT_TRUE(Matches(empty));
1013 TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1014 InstallRegistrySentinel();
1015 base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1016 GROUP_POLICY_OBJECT gpo;
1017 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1018 gpo_list_ = &gpo;
1019 gpo_list_status_ = ERROR_SUCCESS;
1021 PolicyBundle empty;
1022 EXPECT_TRUE(Matches(empty));
1025 TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1026 InstallRegistrySentinel();
1027 GROUP_POLICY_OBJECT gpo;
1028 InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1029 gpo_list_ = &gpo;
1030 gpo_list_status_ = ERROR_SUCCESS;
1032 EXPECT_TRUE(MatchesRegistrySentinel());
1035 TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1036 InstallRegistrySentinel();
1037 base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1038 GROUP_POLICY_OBJECT gpo;
1039 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1040 gpo_list_ = &gpo;
1041 gpo_list_status_ = ERROR_SUCCESS;
1043 EXPECT_TRUE(MatchesRegistrySentinel());
1046 TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1047 InstallRegistrySentinel();
1048 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1049 GROUP_POLICY_OBJECT gpo;
1050 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1051 gpo_list_ = &gpo;
1052 gpo_list_status_ = ERROR_SUCCESS;
1054 EXPECT_TRUE(MatchesTestBundle());
1057 TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1058 InstallRegistrySentinel();
1059 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1060 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1061 GROUP_POLICY_OBJECT gpo1;
1062 GROUP_POLICY_OBJECT gpo2;
1063 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1064 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1065 gpo_list_ = &gpo1;
1066 gpo_list_status_ = ERROR_SUCCESS;
1068 EXPECT_TRUE(MatchesTestBundle());
1071 TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1072 InstallRegistrySentinel();
1073 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1074 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1075 GROUP_POLICY_OBJECT gpo1;
1076 GROUP_POLICY_OBJECT gpo2;
1077 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1078 InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1079 gpo_list_ = &gpo1;
1080 gpo_list_status_ = ERROR_SUCCESS;
1082 EXPECT_TRUE(MatchesTestBundle());
1085 TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1086 InstallRegistrySentinel();
1087 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1088 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1089 GROUP_POLICY_OBJECT gpo1;
1090 GROUP_POLICY_OBJECT gpo2;
1091 InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1092 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1093 gpo_list_ = &gpo1;
1094 gpo_list_status_ = ERROR_SUCCESS;
1096 EXPECT_TRUE(MatchesTestBundle());
1099 TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1100 InstallRegistrySentinel();
1101 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1102 base::FilePath unc_path(L"\\\\some_share\\GPO");
1103 GROUP_POLICY_OBJECT gpo1;
1104 GROUP_POLICY_OBJECT gpo2;
1105 InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1106 InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1107 gpo_list_ = &gpo1;
1108 gpo_list_status_ = ERROR_SUCCESS;
1110 EXPECT_TRUE(MatchesRegistrySentinel());
1113 TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1114 base::FilePath gpo_dir(
1115 test_data_dir_.AppendASCII("extension_alternative_spelling"));
1116 GROUP_POLICY_OBJECT gpo;
1117 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1118 gpo_list_ = &gpo;
1119 gpo_list_status_ = ERROR_SUCCESS;
1121 const char kTestSchema[] =
1123 " \"type\": \"object\","
1124 " \"properties\": {"
1125 " \"policy 1\": { \"type\": \"integer\" },"
1126 " \"policy 2\": { \"type\": \"integer\" }"
1127 " }"
1128 "}";
1129 const PolicyNamespace ns_a(
1130 POLICY_DOMAIN_EXTENSIONS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1131 const PolicyNamespace ns_b(
1132 POLICY_DOMAIN_EXTENSIONS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
1133 ASSERT_TRUE(RegisterSchema(ns_a, kTestSchema));
1134 ASSERT_TRUE(RegisterSchema(ns_b, kTestSchema));
1136 PolicyBundle expected;
1137 base::DictionaryValue expected_a;
1138 expected_a.SetInteger("policy 1", 3);
1139 expected_a.SetInteger("policy 2", 3);
1140 expected.Get(ns_a).LoadFrom(
1141 &expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1142 base::DictionaryValue expected_b;
1143 expected_b.SetInteger("policy 1", 2);
1144 expected.Get(ns_b).LoadFrom(
1145 &expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1146 EXPECT_TRUE(Matches(expected));
1149 TEST_F(PolicyLoaderWinTest, LBSSupport) {
1150 const PolicyNamespace ns(
1151 POLICY_DOMAIN_EXTENSIONS, "heildphpnddilhkemkielfhnkaagiabh");
1152 schema_registry_.RegisterComponent(ns, Schema());
1154 const char kIncompleteSchema[] =
1156 " \"type\": \"object\","
1157 " \"properties\": {"
1158 " \"url_list\": { \"type\": \"array\" },"
1159 " \"url_greylist\": { \"type\": \"array\" }"
1160 " }"
1161 "}";
1163 const base::string16 kPathSuffix =
1164 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions");
1166 base::ListValue list;
1167 list.AppendString("youtube.com");
1168 base::DictionaryValue policy;
1169 policy.Set("url_list", list.DeepCopy());
1170 policy.SetString("alternative_browser_path", "c:\\legacy\\browser.exe");
1171 base::DictionaryValue root;
1172 root.Set(UTF16ToUTF8(kMandatory), policy.DeepCopy());
1173 root.SetString(kSchema, kIncompleteSchema);
1174 EXPECT_TRUE(InstallValue(root, HKEY_LOCAL_MACHINE,
1175 kPathSuffix, ASCIIToUTF16(ns.component_id)));
1177 PolicyBundle expected;
1178 PolicyMap& expected_policy = expected.Get(ns);
1179 expected_policy.Set("alternative_browser_path",
1180 POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1181 new base::StringValue("c:\\legacy\\browser.exe"), NULL);
1182 expected_policy.Set("url_list", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
1183 list.DeepCopy(), NULL);
1184 EXPECT_TRUE(Matches(expected));
1187 } // namespace policy