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 "chrome/browser/policy/policy_loader_win.h"
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 "chrome/browser/policy/async_policy_provider.h"
32 #include "chrome/browser/policy/configuration_policy_provider_test.h"
33 #include "chrome/browser/policy/external_data_fetcher.h"
34 #include "chrome/browser/policy/policy_bundle.h"
35 #include "chrome/browser/policy/policy_map.h"
36 #include "chrome/browser/policy/preg_parser_win.h"
37 #include "components/json_schema/json_schema_constants.h"
38 #include "policy/policy_constants.h"
39 #include "testing/gtest/include/gtest/gtest.h"
41 namespace schema = json_schema_constants;
43 using base::win::RegKey;
49 // Constants for registry key names.
50 const wchar_t kPathSep[] = L"\\";
51 const wchar_t kThirdParty[] = L"3rdparty";
52 const wchar_t kMandatory[] = L"policy";
53 const wchar_t kRecommended[] = L"recommended";
54 const wchar_t kSchema[] = L"schema";
56 // Installs |value| in the given registry |path| and |hive|, under the key
57 // |name|. Returns false on errors.
58 // Some of the possible Value types are stored after a conversion (e.g. doubles
59 // are stored as strings), and can only be retrieved if a corresponding schema
61 bool InstallValue(const base::Value& value,
64 const string16& name) {
65 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet.
66 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS);
67 EXPECT_TRUE(key.Valid());
68 switch (value.GetType()) {
69 case base::Value::TYPE_NULL:
70 return key.WriteValue(name.c_str(), L"") == ERROR_SUCCESS;
72 case base::Value::TYPE_BOOLEAN: {
74 if (!value.GetAsBoolean(&bool_value))
76 return key.WriteValue(name.c_str(), bool_value ? 1 : 0) == ERROR_SUCCESS;
79 case base::Value::TYPE_INTEGER: {
81 if (!value.GetAsInteger(&int_value))
83 return key.WriteValue(name.c_str(), int_value) == ERROR_SUCCESS;
86 case base::Value::TYPE_DOUBLE: {
88 if (!value.GetAsDouble(&double_value))
90 string16 str_value = UTF8ToUTF16(base::DoubleToString(double_value));
91 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
94 case base::Value::TYPE_STRING: {
96 if (!value.GetAsString(&str_value))
98 return key.WriteValue(name.c_str(), str_value.c_str()) == ERROR_SUCCESS;
101 case base::Value::TYPE_DICTIONARY: {
102 const base::DictionaryValue* sub_dict = NULL;
103 if (!value.GetAsDictionary(&sub_dict))
105 for (base::DictionaryValue::Iterator it(*sub_dict);
106 !it.IsAtEnd(); it.Advance()) {
107 if (!InstallValue(it.value(), hive, path + kPathSep + name,
108 UTF8ToUTF16(it.key()))) {
115 case base::Value::TYPE_LIST: {
116 const base::ListValue* list = NULL;
117 if (!value.GetAsList(&list))
119 for (size_t i = 0; i < list->GetSize(); ++i) {
120 const base::Value* item;
121 if (!list->Get(i, &item))
123 if (!InstallValue(*item, hive, path + kPathSep + name,
124 base::UintToString16(i + 1))) {
131 case base::Value::TYPE_BINARY:
138 // Builds a JSON schema that represents the types contained in |value|.
139 // Ownership is transferred to the caller.
140 base::DictionaryValue* BuildSchema(const base::Value& value) {
141 base::DictionaryValue* schema = new base::DictionaryValue();
142 switch (value.GetType()) {
143 case base::Value::TYPE_NULL:
144 schema->SetString(schema::kType, "null");
146 case base::Value::TYPE_BOOLEAN:
147 schema->SetString(schema::kType, "boolean");
149 case base::Value::TYPE_INTEGER:
150 schema->SetString(schema::kType, "integer");
152 case base::Value::TYPE_DOUBLE:
153 schema->SetString(schema::kType, "number");
155 case base::Value::TYPE_STRING:
156 schema->SetString(schema::kType, "string");
159 case base::Value::TYPE_LIST: {
160 // Assumes every list element has the same type.
161 const base::ListValue* list = NULL;
162 if (value.GetAsList(&list) && !list->empty()) {
163 schema->SetString(schema::kType, "array");
164 schema->Set(schema::kItems, BuildSchema(**list->begin()));
169 case base::Value::TYPE_DICTIONARY: {
170 const base::DictionaryValue* dict = NULL;
171 if (value.GetAsDictionary(&dict)) {
172 base::DictionaryValue* properties = new base::DictionaryValue();
173 for (base::DictionaryValue::Iterator it(*dict);
174 !it.IsAtEnd(); it.Advance()) {
175 properties->Set(it.key(), BuildSchema(it.value()));
177 schema->SetString(schema::kType, "object");
178 schema->Set(schema::kProperties, properties);
183 case base::Value::TYPE_BINARY:
189 // Writes a JSON |schema| at the registry entry |name| at |path|
190 // in the given |hive|. Returns false on failure.
191 bool WriteSchema(const base::DictionaryValue& schema,
193 const string16& path,
194 const string16& name) {
196 base::JSONWriter::Write(&schema, &encoded);
199 string16 encoded16 = UTF8ToUTF16(encoded);
200 // KEY_ALL_ACCESS causes the ctor to create the key if it does not exist yet.
201 RegKey key(hive, path.c_str(), KEY_ALL_ACCESS);
202 EXPECT_TRUE(key.Valid());
203 return key.WriteValue(name.c_str(), encoded16.c_str()) == ERROR_SUCCESS;
206 // Builds a JSON schema for |value| and writes it at the registry entry |name|
207 // at |path| in the given |hive|. Returns false on failure.
208 bool InstallSchema(const base::Value& value,
210 const string16& path,
211 const string16& name) {
212 scoped_ptr<base::DictionaryValue> schema_dict(BuildSchema(value));
213 return WriteSchema(*schema_dict, hive, path, name);
216 // This class provides sandboxing and mocking for the parts of the Windows
217 // Registry implementing Group Policy. It prepares two temporary sandbox keys,
218 // one for HKLM and one for HKCU. A test's calls to the registry are redirected
219 // by Windows to these sandboxes, allowing the tests to manipulate and access
220 // policy as if it were active, but without actually changing the parts of the
221 // Registry that are managed by Group Policy.
222 class ScopedGroupPolicyRegistrySandbox {
224 ScopedGroupPolicyRegistrySandbox();
225 ~ScopedGroupPolicyRegistrySandbox();
228 void ActivateOverrides();
229 void RemoveOverrides();
231 // Deletes the sandbox keys.
234 std::wstring key_name_;
236 // Keys are created for the lifetime of a test to contain
237 // the sandboxed HKCU and HKLM hives, respectively.
238 RegKey temp_hkcu_hive_key_;
239 RegKey temp_hklm_hive_key_;
241 DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox);
244 // A test harness that feeds policy via the Chrome GPO registry subtree.
245 class RegistryTestHarness : public PolicyProviderTestHarness,
246 public AppliedGPOListProvider {
248 RegistryTestHarness(HKEY hive, PolicyScope scope);
249 virtual ~RegistryTestHarness();
251 // PolicyProviderTestHarness:
252 virtual void SetUp() OVERRIDE;
254 virtual ConfigurationPolicyProvider* CreateProvider(
255 scoped_refptr<base::SequencedTaskRunner> task_runner,
256 const PolicyDefinitionList* policy_list) OVERRIDE;
258 virtual void InstallEmptyPolicy() OVERRIDE;
259 virtual void InstallStringPolicy(const std::string& policy_name,
260 const std::string& policy_value) OVERRIDE;
261 virtual void InstallIntegerPolicy(const std::string& policy_name,
262 int policy_value) OVERRIDE;
263 virtual void InstallBooleanPolicy(const std::string& policy_name,
264 bool policy_value) OVERRIDE;
265 virtual void InstallStringListPolicy(
266 const std::string& policy_name,
267 const base::ListValue* policy_value) OVERRIDE;
268 virtual void InstallDictionaryPolicy(
269 const std::string& policy_name,
270 const base::DictionaryValue* policy_value) OVERRIDE;
271 virtual void Install3rdPartyPolicy(
272 const base::DictionaryValue* policies) OVERRIDE;
274 // AppliedGPOListProvider:
275 virtual DWORD GetAppliedGPOList(DWORD flags,
276 LPCTSTR machine_name,
278 GUID* extension_guid,
279 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
280 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
282 // Creates a harness instance that will install policy in HKCU or HKLM,
284 static PolicyProviderTestHarness* CreateHKCU();
285 static PolicyProviderTestHarness* CreateHKLM();
290 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
292 DISALLOW_COPY_AND_ASSIGN(RegistryTestHarness);
295 // A test harness that generates PReg files for the provider to read.
296 class PRegTestHarness : public PolicyProviderTestHarness,
297 public AppliedGPOListProvider {
300 virtual ~PRegTestHarness();
302 // PolicyProviderTestHarness:
303 virtual void SetUp() OVERRIDE;
305 virtual ConfigurationPolicyProvider* CreateProvider(
306 scoped_refptr<base::SequencedTaskRunner> task_runner,
307 const PolicyDefinitionList* policy_list) OVERRIDE;
309 virtual void InstallEmptyPolicy() OVERRIDE;
310 virtual void InstallStringPolicy(const std::string& policy_name,
311 const std::string& policy_value) OVERRIDE;
312 virtual void InstallIntegerPolicy(const std::string& policy_name,
313 int policy_value) OVERRIDE;
314 virtual void InstallBooleanPolicy(const std::string& policy_name,
315 bool policy_value) OVERRIDE;
316 virtual void InstallStringListPolicy(
317 const std::string& policy_name,
318 const base::ListValue* policy_value) OVERRIDE;
319 virtual void InstallDictionaryPolicy(
320 const std::string& policy_name,
321 const base::DictionaryValue* policy_value) OVERRIDE;
322 virtual void Install3rdPartyPolicy(
323 const base::DictionaryValue* policies) OVERRIDE;
325 // AppliedGPOListProvider:
326 virtual DWORD GetAppliedGPOList(DWORD flags,
327 LPCTSTR machine_name,
329 GUID* extension_guid,
330 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE;
331 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE;
333 // Creates a harness instance.
334 static PolicyProviderTestHarness* Create();
337 // Helper to append a string16 to an uint8 buffer.
338 static void AppendChars(std::vector<uint8>* buffer, const string16& chars);
340 // Appends a record with the given fields to the PReg file.
341 void AppendRecordToPRegFile(const string16& path,
342 const std::string& key,
347 // Appends the given DWORD |value| for |path| + |key| to the PReg file.
348 void AppendDWORDToPRegFile(const string16& path,
349 const std::string& key,
352 // Appends the given string |value| for |path| + |key| to the PReg file.
353 void AppendStringToPRegFile(const string16& path,
354 const std::string& key,
355 const std::string& value);
357 // Appends the given policy |value| for |path| + |key| to the PReg file,
358 // converting and recursing as necessary.
359 void AppendPolicyToPRegFile(const string16& path,
360 const std::string& key,
361 const base::Value* value);
363 base::ScopedTempDir temp_dir_;
364 base::FilePath preg_file_path_;
365 GROUP_POLICY_OBJECT gpo_;
367 DISALLOW_COPY_AND_ASSIGN(PRegTestHarness);
370 ScopedGroupPolicyRegistrySandbox::ScopedGroupPolicyRegistrySandbox() {
371 // Generate a unique registry key for the override for each test. This
372 // makes sure that tests executing in parallel won't delete each other's
373 // key, at DeleteKeys().
374 key_name_ = ASCIIToWide(base::StringPrintf(
375 "SOFTWARE\\chromium unittest %d",
376 base::Process::Current().pid()));
377 std::wstring hklm_key_name = key_name_ + L"\\HKLM";
378 std::wstring hkcu_key_name = key_name_ + L"\\HKCU";
380 // Create the subkeys to hold the overridden HKLM and HKCU
382 temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
383 hklm_key_name.c_str(),
385 temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
386 hkcu_key_name.c_str(),
392 ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() {
397 void ScopedGroupPolicyRegistrySandbox::ActivateOverrides() {
398 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE,
399 temp_hklm_hive_key_.Handle()));
400 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER,
401 temp_hkcu_hive_key_.Handle()));
404 void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() {
405 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0));
406 ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0));
409 void ScopedGroupPolicyRegistrySandbox::DeleteKeys() {
410 RegKey key(HKEY_CURRENT_USER, key_name_.c_str(), KEY_ALL_ACCESS);
411 ASSERT_TRUE(key.Valid());
415 RegistryTestHarness::RegistryTestHarness(HKEY hive, PolicyScope scope)
416 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {}
418 RegistryTestHarness::~RegistryTestHarness() {}
420 void RegistryTestHarness::SetUp() {}
422 ConfigurationPolicyProvider* RegistryTestHarness::CreateProvider(
423 scoped_refptr<base::SequencedTaskRunner> task_runner,
424 const PolicyDefinitionList* policy_list) {
425 scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(
426 task_runner, policy_list, kRegistryChromePolicyKey, this));
427 return new AsyncPolicyProvider(loader.Pass());
430 void RegistryTestHarness::InstallEmptyPolicy() {}
432 void RegistryTestHarness::InstallStringPolicy(
433 const std::string& policy_name,
434 const std::string& policy_value) {
435 RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS);
436 ASSERT_TRUE(key.Valid());
437 ASSERT_HRESULT_SUCCEEDED(key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
438 UTF8ToUTF16(policy_value).c_str()));
441 void RegistryTestHarness::InstallIntegerPolicy(
442 const std::string& policy_name,
444 RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS);
445 ASSERT_TRUE(key.Valid());
446 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
447 static_cast<DWORD>(policy_value));
450 void RegistryTestHarness::InstallBooleanPolicy(
451 const std::string& policy_name,
453 RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS);
454 ASSERT_TRUE(key.Valid());
455 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
456 static_cast<DWORD>(policy_value));
459 void RegistryTestHarness::InstallStringListPolicy(
460 const std::string& policy_name,
461 const base::ListValue* policy_value) {
463 (string16(kRegistryChromePolicyKey) + ASCIIToUTF16("\\") +
464 UTF8ToUTF16(policy_name)).c_str(),
466 ASSERT_TRUE(key.Valid());
468 for (base::ListValue::const_iterator element(policy_value->begin());
469 element != policy_value->end();
471 std::string element_value;
472 if (!(*element)->GetAsString(&element_value))
474 std::string name(base::IntToString(index++));
475 key.WriteValue(UTF8ToUTF16(name).c_str(),
476 UTF8ToUTF16(element_value).c_str());
480 void RegistryTestHarness::InstallDictionaryPolicy(
481 const std::string& policy_name,
482 const base::DictionaryValue* policy_value) {
484 base::JSONWriter::Write(policy_value, &json);
485 RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS);
486 ASSERT_TRUE(key.Valid());
487 key.WriteValue(UTF8ToUTF16(policy_name).c_str(),
488 UTF8ToUTF16(json).c_str());
491 void RegistryTestHarness::Install3rdPartyPolicy(
492 const base::DictionaryValue* policies) {
493 // The first level entries are domains, and the second level entries map
494 // components to their policy.
495 const string16 kPathPrefix = string16(kRegistryChromePolicyKey) + kPathSep +
496 kThirdParty + kPathSep;
497 for (base::DictionaryValue::Iterator domain(*policies);
498 !domain.IsAtEnd(); domain.Advance()) {
499 const base::DictionaryValue* components = NULL;
500 if (!domain.value().GetAsDictionary(&components)) {
504 for (base::DictionaryValue::Iterator component(*components);
505 !component.IsAtEnd(); component.Advance()) {
506 const string16 path = kPathPrefix +
507 UTF8ToUTF16(domain.key()) + kPathSep +
508 UTF8ToUTF16(component.key());
509 InstallValue(component.value(), hive_, path, kMandatory);
510 EXPECT_TRUE(InstallSchema(component.value(), hive_, path, kSchema));
515 DWORD RegistryTestHarness::GetAppliedGPOList(DWORD flags,
516 LPCTSTR machine_name,
518 GUID* extension_guid,
519 PGROUP_POLICY_OBJECT* gpo_list) {
521 return ERROR_ACCESS_DENIED;
524 BOOL RegistryTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
529 PolicyProviderTestHarness* RegistryTestHarness::CreateHKCU() {
530 return new RegistryTestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER);
534 PolicyProviderTestHarness* RegistryTestHarness::CreateHKLM() {
535 return new RegistryTestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE);
538 PRegTestHarness::PRegTestHarness()
539 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE) {}
541 PRegTestHarness::~PRegTestHarness() {}
543 void PRegTestHarness::SetUp() {
544 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
545 preg_file_path_ = temp_dir_.path().Append(PolicyLoaderWin::kPRegFileName);
546 ASSERT_TRUE(file_util::WriteFile(preg_file_path_,
547 preg_parser::kPRegFileHeader,
548 arraysize(preg_parser::kPRegFileHeader)));
550 memset(&gpo_, 0, sizeof(GROUP_POLICY_OBJECT));
551 gpo_.lpFileSysPath = const_cast<wchar_t*>(temp_dir_.path().value().c_str());
554 ConfigurationPolicyProvider* PRegTestHarness::CreateProvider(
555 scoped_refptr<base::SequencedTaskRunner> task_runner,
556 const PolicyDefinitionList* policy_list) {
557 scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(
558 task_runner, policy_list, kRegistryChromePolicyKey, this));
559 return new AsyncPolicyProvider(loader.Pass());
562 void PRegTestHarness::InstallEmptyPolicy() {}
564 void PRegTestHarness::InstallStringPolicy(const std::string& policy_name,
565 const std::string& policy_value) {
566 AppendStringToPRegFile(kRegistryChromePolicyKey, policy_name, policy_value);
569 void PRegTestHarness::InstallIntegerPolicy(const std::string& policy_name,
571 AppendDWORDToPRegFile(kRegistryChromePolicyKey, policy_name, policy_value);
574 void PRegTestHarness::InstallBooleanPolicy(const std::string& policy_name,
576 AppendDWORDToPRegFile(kRegistryChromePolicyKey, policy_name, policy_value);
579 void PRegTestHarness::InstallStringListPolicy(
580 const std::string& policy_name,
581 const base::ListValue* policy_value) {
582 AppendPolicyToPRegFile(kRegistryChromePolicyKey, policy_name, policy_value);
585 void PRegTestHarness::InstallDictionaryPolicy(
586 const std::string& policy_name,
587 const base::DictionaryValue* policy_value) {
589 base::JSONWriter::Write(policy_value, &json);
590 AppendStringToPRegFile(kRegistryChromePolicyKey, policy_name, json);
593 void PRegTestHarness::Install3rdPartyPolicy(
594 const base::DictionaryValue* policies) {
595 // The first level entries are domains, and the second level entries map
596 // components to their policy.
597 const string16 kPathPrefix = string16(kRegistryChromePolicyKey) + kPathSep +
598 kThirdParty + kPathSep;
599 for (base::DictionaryValue::Iterator domain(*policies);
600 !domain.IsAtEnd(); domain.Advance()) {
601 const base::DictionaryValue* components = NULL;
602 if (!domain.value().GetAsDictionary(&components)) {
606 const string16 domain_path = kPathPrefix + UTF8ToUTF16(domain.key());
607 for (base::DictionaryValue::Iterator component(*components);
608 !component.IsAtEnd(); component.Advance()) {
609 const string16 component_path =
610 domain_path + kPathSep + UTF8ToUTF16(component.key());
611 AppendPolicyToPRegFile(component_path, UTF16ToUTF8(kMandatory),
614 scoped_ptr<base::DictionaryValue> schema_dict(
615 BuildSchema(component.value()));
616 std::string schema_json;
617 base::JSONWriter::Write(schema_dict.get(), &schema_json);
618 if (!schema_json.empty()) {
619 AppendStringToPRegFile(component_path, UTF16ToUTF8(kSchema),
626 DWORD PRegTestHarness::GetAppliedGPOList(DWORD flags,
627 LPCTSTR machine_name,
629 GUID* extension_guid,
630 PGROUP_POLICY_OBJECT* gpo_list) {
631 *gpo_list = flags & GPO_LIST_FLAG_MACHINE ? &gpo_ : NULL;
632 return ERROR_SUCCESS;
635 BOOL PRegTestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) {
640 PolicyProviderTestHarness* PRegTestHarness::Create() {
641 return new PRegTestHarness();
645 void PRegTestHarness::AppendChars(std::vector<uint8>* buffer,
646 const string16& chars) {
647 for (string16::const_iterator c(chars.begin()); c != chars.end(); ++c) {
648 buffer->push_back(*c & 0xff);
649 buffer->push_back((*c >> 8) & 0xff);
653 void PRegTestHarness::AppendRecordToPRegFile(const string16& path,
654 const std::string& key,
658 std::vector<uint8> buffer;
659 AppendChars(&buffer, L"[");
660 AppendChars(&buffer, path);
661 AppendChars(&buffer, string16(L"\0;", 2));
662 AppendChars(&buffer, UTF8ToUTF16(key));
663 AppendChars(&buffer, string16(L"\0;", 2));
664 type = base::ByteSwapToLE32(type);
665 uint8* type_data = reinterpret_cast<uint8*>(&type);
666 buffer.insert(buffer.end(), type_data, type_data + sizeof(DWORD));
667 AppendChars(&buffer, L";");
668 size = base::ByteSwapToLE32(size);
669 uint8* size_data = reinterpret_cast<uint8*>(&size);
670 buffer.insert(buffer.end(), size_data, size_data + sizeof(DWORD));
671 AppendChars(&buffer, L";");
672 buffer.insert(buffer.end(), data, data + size);
673 AppendChars(&buffer, L"]");
675 ASSERT_EQ(buffer.size(),
676 file_util::AppendToFile(
678 reinterpret_cast<const char*>(vector_as_array(&buffer)),
682 void PRegTestHarness::AppendDWORDToPRegFile(const string16& path,
683 const std::string& key,
685 value = base::ByteSwapToLE32(value);
686 AppendRecordToPRegFile(path, key, REG_DWORD, sizeof(DWORD),
687 reinterpret_cast<uint8*>(&value));
690 void PRegTestHarness::AppendStringToPRegFile(const string16& path,
691 const std::string& key,
692 const std::string& value) {
693 string16 string16_value(UTF8ToUTF16(value));
694 std::vector<char16> data;
695 std::transform(string16_value.begin(), string16_value.end(),
696 std::back_inserter(data), std::ptr_fun(base::ByteSwapToLE16));
697 data.push_back(base::ByteSwapToLE16(L'\0'));
699 AppendRecordToPRegFile(path, key, REG_SZ, data.size() * sizeof(char16),
700 reinterpret_cast<uint8*>(vector_as_array(&data)));
703 void PRegTestHarness::AppendPolicyToPRegFile(const string16& path,
704 const std::string& key,
705 const base::Value* value) {
706 switch (value->GetType()) {
707 case base::Value::TYPE_BOOLEAN: {
708 bool boolean_value = false;
709 ASSERT_TRUE(value->GetAsBoolean(&boolean_value));
710 AppendDWORDToPRegFile(path, key, boolean_value);
713 case base::Value::TYPE_INTEGER: {
715 ASSERT_TRUE(value->GetAsInteger(&int_value));
716 AppendDWORDToPRegFile(path, key, int_value);
719 case base::Value::TYPE_DOUBLE: {
720 double double_value = 0;
721 ASSERT_TRUE(value->GetAsDouble(&double_value));
722 AppendStringToPRegFile(path, key, base::DoubleToString(double_value));
725 case base::Value::TYPE_STRING: {
726 std::string string_value;
727 ASSERT_TRUE(value->GetAsString(&string_value));
728 AppendStringToPRegFile(path, key, string_value);
731 case base::Value::TYPE_DICTIONARY: {
732 string16 subpath = path + kPathSep + UTF8ToUTF16(key);
733 const base::DictionaryValue* dict = NULL;
734 ASSERT_TRUE(value->GetAsDictionary(&dict));
735 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
737 AppendPolicyToPRegFile(subpath, entry.key(), &entry.value());
741 case base::Value::TYPE_LIST: {
742 string16 subpath = path + kPathSep + UTF8ToUTF16(key);
743 const base::ListValue* list = NULL;
744 ASSERT_TRUE(value->GetAsList(&list));
745 for (size_t i = 0; i < list->GetSize(); ++i) {
746 const base::Value* entry = NULL;
747 ASSERT_TRUE(list->Get(i, &entry));
748 AppendPolicyToPRegFile(subpath, base::IntToString(i + 1), entry);
752 case base::Value::TYPE_BINARY:
753 case base::Value::TYPE_NULL: {
762 // Instantiate abstract test case for basic policy reading tests.
763 INSTANTIATE_TEST_CASE_P(
764 PolicyProviderWinTest,
765 ConfigurationPolicyProviderTest,
766 testing::Values(RegistryTestHarness::CreateHKCU,
767 RegistryTestHarness::CreateHKLM,
768 PRegTestHarness::Create));
770 // Instantiate abstract test case for 3rd party policy reading tests.
771 INSTANTIATE_TEST_CASE_P(
772 ThirdPartyPolicyProviderWinTest,
773 Configuration3rdPartyPolicyProviderTest,
774 testing::Values(RegistryTestHarness::CreateHKCU,
775 RegistryTestHarness::CreateHKLM,
776 PRegTestHarness::Create));
778 // Test cases for windows policy provider specific functionality.
779 class PolicyLoaderWinTest : public PolicyTestBase,
780 public AppliedGPOListProvider {
782 // The policy key this tests places data under. This must match the data
783 // files in chrome/test/data/policy/gpo.
784 static const char16 kTestPolicyKey[];
786 PolicyLoaderWinTest()
788 gpo_list_status_(ERROR_ACCESS_DENIED) {}
789 virtual ~PolicyLoaderWinTest() {}
791 virtual void SetUp() OVERRIDE {
792 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
793 test_data_dir_ = test_data_dir_.AppendASCII("chrome")
796 .AppendASCII("policy")
800 // AppliedGPOListProvider:
801 virtual DWORD GetAppliedGPOList(DWORD flags,
802 LPCTSTR machine_name,
804 GUID* extension_guid,
805 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
806 *gpo_list = gpo_list_;
807 return gpo_list_status_;
809 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
813 void InitGPO(GROUP_POLICY_OBJECT* gpo,
815 const base::FilePath& path,
816 GROUP_POLICY_OBJECT* next,
817 GROUP_POLICY_OBJECT* prev) {
818 memset(gpo, 0, sizeof(GROUP_POLICY_OBJECT));
819 gpo->dwOptions = options;
820 gpo->lpFileSysPath = const_cast<wchar_t*>(path.value().c_str());
825 bool Matches(const PolicyBundle& expected) {
826 PolicyLoaderWin loader(loop_.message_loop_proxy(),
827 &test_policy_definitions::kList, kTestPolicyKey,
829 scoped_ptr<PolicyBundle> loaded(loader.Load());
830 return loaded->Equals(expected);
833 void InstallRegistrySentinel() {
834 RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
835 ASSERT_TRUE(hklm_key.Valid());
837 UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(),
838 UTF8ToUTF16("registry").c_str());
841 bool MatchesRegistrySentinel() {
842 base::DictionaryValue expected_policy;
843 expected_policy.SetString(test_policy_definitions::kKeyString, "registry");
844 PolicyBundle expected;
845 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
846 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
847 return Matches(expected);
850 bool MatchesTestBundle() {
851 base::DictionaryValue expected_policy;
852 expected_policy.SetBoolean(test_policy_definitions::kKeyBoolean, true);
853 expected_policy.SetString(test_policy_definitions::kKeyString, "GPO");
854 expected_policy.SetInteger(test_policy_definitions::kKeyInteger, 42);
855 scoped_ptr<base::ListValue> list(new base::ListValue());
856 list->AppendString("GPO 1");
857 list->AppendString("GPO 2");
858 expected_policy.Set(test_policy_definitions::kKeyStringList,
860 PolicyBundle expected;
861 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
862 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY,
863 POLICY_SCOPE_MACHINE);
864 return Matches(expected);
867 ScopedGroupPolicyRegistrySandbox registry_sandbox_;
868 PGROUP_POLICY_OBJECT gpo_list_;
869 DWORD gpo_list_status_;
870 base::FilePath test_data_dir_;
873 const char16 PolicyLoaderWinTest::kTestPolicyKey[] =
874 L"SOFTWARE\\Policies\\Chromium";
876 TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) {
877 RegKey hklm_key(HKEY_LOCAL_MACHINE, kTestPolicyKey, KEY_ALL_ACCESS);
878 ASSERT_TRUE(hklm_key.Valid());
879 hklm_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(),
880 UTF8ToUTF16("hklm").c_str());
881 RegKey hkcu_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS);
882 ASSERT_TRUE(hkcu_key.Valid());
883 hkcu_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(),
884 UTF8ToUTF16("hkcu").c_str());
886 PolicyBundle expected;
887 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
888 .Set(test_policy_definitions::kKeyString,
889 POLICY_LEVEL_MANDATORY,
890 POLICY_SCOPE_MACHINE,
891 base::Value::CreateStringValue("hklm"), NULL);
892 EXPECT_TRUE(Matches(expected));
895 TEST_F(PolicyLoaderWinTest, Load3rdPartyWithoutSchema) {
896 base::DictionaryValue dict;
897 dict.SetString("str", "string value");
898 dict.SetInteger("int", 123);
899 dict.Set("subdict", dict.DeepCopy());
900 dict.Set("subsubdict", dict.DeepCopy());
901 dict.Set("subsubsubdict", dict.DeepCopy());
903 base::DictionaryValue policy_dict;
904 policy_dict.Set("extensions.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.policy",
906 policy_dict.Set("extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.policy",
908 EXPECT_TRUE(InstallValue(policy_dict, HKEY_LOCAL_MACHINE,
909 kTestPolicyKey, kThirdParty));
911 PolicyBundle expected;
912 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
913 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
914 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
915 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
916 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
917 .LoadFrom(&dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
918 EXPECT_TRUE(Matches(expected));
921 TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) {
922 // Policy for the same extension will be provided at the 4 level/scope
923 // combinations, to verify that they overlap as expected.
925 const string16 kPathSuffix =
926 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge");
928 const char kUserMandatory[] = "user-mandatory";
929 const char kUserRecommended[] = "user-recommended";
930 const char kMachineMandatory[] = "machine-mandatory";
931 const char kMachineRecommended[] = "machine-recommended";
933 base::DictionaryValue policy;
934 policy.SetString("a", kMachineMandatory);
935 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
936 kPathSuffix, kMandatory));
937 policy.SetString("a", kUserMandatory);
938 policy.SetString("b", kUserMandatory);
939 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
940 kPathSuffix, kMandatory));
941 policy.SetString("a", kMachineRecommended);
942 policy.SetString("b", kMachineRecommended);
943 policy.SetString("c", kMachineRecommended);
944 EXPECT_TRUE(InstallValue(policy, HKEY_LOCAL_MACHINE,
945 kPathSuffix, kRecommended));
946 policy.SetString("a", kUserRecommended);
947 policy.SetString("b", kUserRecommended);
948 policy.SetString("c", kUserRecommended);
949 policy.SetString("d", kUserRecommended);
950 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER,
951 kPathSuffix, kRecommended));
953 PolicyBundle expected;
954 PolicyMap& expected_policy =
955 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "merge"));
956 expected_policy.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
957 base::Value::CreateStringValue(kMachineMandatory), NULL);
958 expected_policy.Set("b", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
959 base::Value::CreateStringValue(kUserMandatory), NULL);
960 expected_policy.Set("c", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
961 base::Value::CreateStringValue(kMachineRecommended),
963 expected_policy.Set("d", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
964 base::Value::CreateStringValue(kUserRecommended), NULL);
965 EXPECT_TRUE(Matches(expected));
968 TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) {
969 // Create a dictionary with all the types that can be stored encoded in a
970 // string, to pass to InstallSchema(). Also build an equivalent dictionary
971 // with the encoded values, to pass to InstallValue().
972 base::DictionaryValue policy;
973 policy.Set("null", base::Value::CreateNullValue());
974 policy.SetBoolean("bool", true);
975 policy.SetInteger("int", -123);
976 policy.SetDouble("double", 456.78e9);
977 base::ListValue list;
978 list.Append(policy.DeepCopy());
979 list.Append(policy.DeepCopy());
980 policy.Set("list", list.DeepCopy());
981 // Encode |policy| before adding the "dict" entry.
982 std::string encoded_dict;
983 base::JSONWriter::Write(&policy, &encoded_dict);
984 ASSERT_FALSE(encoded_dict.empty());
985 policy.Set("dict", policy.DeepCopy());
987 std::string encoded_list;
988 base::JSONWriter::Write(&list, &encoded_list);
989 ASSERT_FALSE(encoded_list.empty());
990 base::DictionaryValue encoded_policy;
991 encoded_policy.SetString("null", "");
992 encoded_policy.SetString("bool", "1");
993 encoded_policy.SetString("int", "-123");
994 encoded_policy.SetString("double", "456.78e9");
995 encoded_policy.SetString("list", encoded_list);
996 encoded_policy.SetString("dict", encoded_dict);
998 const string16 kPathSuffix =
999 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\string");
1000 EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema));
1002 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
1004 PolicyBundle expected;
1005 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "string"))
1006 .LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1007 EXPECT_TRUE(Matches(expected));
1010 TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) {
1011 base::DictionaryValue policy;
1012 policy.SetBoolean("bool", true);
1013 policy.SetInteger("int", 123);
1014 policy.SetDouble("double", 456.0);
1016 base::DictionaryValue encoded_policy;
1017 encoded_policy.SetInteger("bool", 1);
1018 encoded_policy.SetInteger("int", 123);
1019 encoded_policy.SetInteger("double", 456);
1021 const string16 kPathSuffix =
1022 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\int");
1023 EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema));
1025 InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
1027 PolicyBundle expected;
1028 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "int"))
1029 .LoadFrom(&policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1030 EXPECT_TRUE(Matches(expected));
1033 TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) {
1034 // Build a schema for an "object" with a default schema for its properties.
1035 base::DictionaryValue default_schema;
1036 default_schema.SetString(schema::kType, "number");
1037 base::DictionaryValue integer_schema;
1038 integer_schema.SetString(schema::kType, "integer");
1039 base::DictionaryValue properties;
1040 properties.Set("special-int1", integer_schema.DeepCopy());
1041 properties.Set("special-int2", integer_schema.DeepCopy());
1042 base::DictionaryValue schema;
1043 schema.SetString(schema::kType, "object");
1044 schema.Set(schema::kProperties, properties.DeepCopy());
1045 schema.Set(schema::kAdditionalProperties, default_schema.DeepCopy());
1047 const string16 kPathSuffix =
1048 kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\test");
1049 EXPECT_TRUE(WriteSchema(schema, HKEY_CURRENT_USER, kPathSuffix, kSchema));
1051 // Write some test values.
1052 base::DictionaryValue policy;
1053 // These special values have a specific schema for them.
1054 policy.SetInteger("special-int1", 123);
1055 policy.SetString("special-int2", "-456");
1056 // Other values default to be loaded as doubles.
1057 policy.SetInteger("double1", 789.0);
1058 policy.SetString("double2", "123.456e7");
1059 policy.SetString("invalid", "omg");
1060 EXPECT_TRUE(InstallValue(policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory));
1062 base::DictionaryValue expected_policy;
1063 expected_policy.SetInteger("special-int1", 123);
1064 expected_policy.SetInteger("special-int2", -456);
1065 expected_policy.SetDouble("double1", 789.0);
1066 expected_policy.SetDouble("double2", 123.456e7);
1067 expected_policy.Set("invalid", base::Value::CreateNullValue());
1068 PolicyBundle expected;
1069 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "test"))
1070 .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
1071 EXPECT_TRUE(Matches(expected));
1074 TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) {
1075 InstallRegistrySentinel();
1077 gpo_list_status_ = ERROR_SUCCESS;
1080 EXPECT_TRUE(Matches(empty));
1083 TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) {
1084 InstallRegistrySentinel();
1085 base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty"));
1086 GROUP_POLICY_OBJECT gpo;
1087 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1089 gpo_list_status_ = ERROR_SUCCESS;
1092 EXPECT_TRUE(Matches(empty));
1095 TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) {
1096 InstallRegistrySentinel();
1097 GROUP_POLICY_OBJECT gpo;
1098 InitGPO(&gpo, 0, test_data_dir_, NULL, NULL);
1100 gpo_list_status_ = ERROR_SUCCESS;
1102 EXPECT_TRUE(MatchesRegistrySentinel());
1105 TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) {
1106 InstallRegistrySentinel();
1107 base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad"));
1108 GROUP_POLICY_OBJECT gpo;
1109 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1111 gpo_list_status_ = ERROR_SUCCESS;
1113 EXPECT_TRUE(MatchesRegistrySentinel());
1116 TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) {
1117 InstallRegistrySentinel();
1118 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1119 GROUP_POLICY_OBJECT gpo;
1120 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1122 gpo_list_status_ = ERROR_SUCCESS;
1124 EXPECT_TRUE(MatchesTestBundle());
1127 TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) {
1128 InstallRegistrySentinel();
1129 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2"));
1130 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1"));
1131 GROUP_POLICY_OBJECT gpo1;
1132 GROUP_POLICY_OBJECT gpo2;
1133 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1134 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1136 gpo_list_status_ = ERROR_SUCCESS;
1138 EXPECT_TRUE(MatchesTestBundle());
1141 TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) {
1142 InstallRegistrySentinel();
1143 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1144 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1145 GROUP_POLICY_OBJECT gpo1;
1146 GROUP_POLICY_OBJECT gpo2;
1147 InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL);
1148 InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1);
1150 gpo_list_status_ = ERROR_SUCCESS;
1152 EXPECT_TRUE(MatchesTestBundle());
1155 TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) {
1156 InstallRegistrySentinel();
1157 base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1"));
1158 base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2"));
1159 GROUP_POLICY_OBJECT gpo1;
1160 GROUP_POLICY_OBJECT gpo2;
1161 InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL);
1162 InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1);
1164 gpo_list_status_ = ERROR_SUCCESS;
1166 EXPECT_TRUE(MatchesTestBundle());
1169 TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) {
1170 InstallRegistrySentinel();
1171 base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1"));
1172 base::FilePath unc_path(L"\\\\some_share\\GPO");
1173 GROUP_POLICY_OBJECT gpo1;
1174 GROUP_POLICY_OBJECT gpo2;
1175 InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL);
1176 InitGPO(&gpo2, 0, unc_path, NULL, &gpo1);
1178 gpo_list_status_ = ERROR_SUCCESS;
1180 EXPECT_TRUE(MatchesRegistrySentinel());
1183 TEST_F(PolicyLoaderWinTest, LoadExtensionPolicyAlternativeSpelling) {
1184 base::FilePath gpo_dir(
1185 test_data_dir_.AppendASCII("extension_alternative_spelling"));
1186 GROUP_POLICY_OBJECT gpo;
1187 InitGPO(&gpo, 0, gpo_dir, NULL, NULL);
1189 gpo_list_status_ = ERROR_SUCCESS;
1191 PolicyBundle expected;
1192 base::DictionaryValue expected_a;
1193 expected_a.SetInteger("policy 1", 3);
1194 expected_a.SetInteger("policy 2", 3);
1195 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
1196 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
1197 .LoadFrom(&expected_a, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1198 base::DictionaryValue expected_b;
1199 expected_b.SetInteger("policy 1", 2);
1200 expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
1201 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
1202 .LoadFrom(&expected_b, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
1203 EXPECT_TRUE(Matches(expected));
1206 } // namespace policy