diff options
Diffstat (limited to 'chromium/components/policy/tools/generate_policy_source_test.py')
-rwxr-xr-x | chromium/components/policy/tools/generate_policy_source_test.py | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/chromium/components/policy/tools/generate_policy_source_test.py b/chromium/components/policy/tools/generate_policy_source_test.py new file mode 100755 index 00000000000..26282724ca0 --- /dev/null +++ b/chromium/components/policy/tools/generate_policy_source_test.py @@ -0,0 +1,473 @@ +#!/usr/bin/env python3 +# Copyright 2016 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. + +import codecs +import unittest +from unittest.mock import patch, mock_open, call +from typing import NamedTuple + +import generate_policy_source +import generate_policy_source_test_data as test_data + +from generate_policy_source import PolicyDetails + + +class PolicyData(NamedTuple): + policy_id: int + chunk_number: int + field_number: int + + +class PolicyGenerationTest(unittest.TestCase): + + TEMPLATES_JSON = { + "risk_tag_definitions": [{ + "name": "full-admin-access", + "description": "full-admin-access-desc", + "user-description": "full-admin-access-user-desc" + }], + "policy_definitions": [{ + "name": "ExampleStringPolicy", + "type": "string", + "schema": { + "type": "string" + }, + "supported_on": ["chrome_os:1-"], + "id": 1, + "tags": [], + "caption": "ExampleStringPolicy caption", + "desc": "ExampleStringPolicy desc" + }, { + "name": "ExampleBoolPolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "id": 2, + "tags": [], + "caption": "ExampleBoolPolicy caption", + "desc": "ExampleBoolPolicy desc", + }, { + "name": "ExampleBoolMergeMetapolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "features": { + "metapolicy_type": "merge", + }, + "id": 3, + "tags": [], + "caption": "ExampleBoolMergeMetapolicy caption", + "desc": "ExampleBoolMergeMetapolicy desc", + }, { + "name": "ExampleBoolPrecedenceMetapolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "features": { + "metapolicy_type": "precedence", + }, + "id": 4, + "tags": [], + "caption": "ExampleBoolPrecedenceMetapolicy caption", + "desc": "ExampleBoolPrecedenceMetapolicy desc", + }, { + "name": "CloudOnlyPolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "features": { + "cloud_only": True, + }, + "supported_on": ["chrome_os:1-", "android:1-"], + "id": 5, + "tags": [], + "caption": "CloudOnlyPolicy caption", + "desc": "CloudOnlyPolicy desc", + }, { + "name": "CloudManagementEnrollmentToken", + "type": "string", + "schema": { + "type": "string" + }, + "supported_on": ["chrome_os:1-", "android:1-"], + "id": 6, + "tags": [], + "caption": "CloudManagementEnrollmentToken caption", + "desc": "CloudManagementEnrollmentToken desc" + }, { + "name": "ChunkZeroLastFieldBooleanPolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "id": 1015, + "tags": [], + "caption": "ChunkZeroLastFieldBooleanPolicy caption", + "desc": "ChunkZeroLastFieldBooleanPolicy desc.", + }, { + "name": "ChunkOneFirstFieldBooleanPolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "id": 1016, + "tags": [], + "caption": "ChunkOneFirstFieldBooleanPolicy caption", + "desc": "ChunkOneFirstFieldBooleanPolicy desc.", + }, { + "name": "ChunkOneLastFieldBooleanPolicy", + "type": "main", + "schema": { + "type": "boolean" + }, + "supported_on": ["chrome_os:1-"], + "id": 1815, + "tags": [], + "caption": "ChunkOneLastFieldBooleanPolicy caption", + "desc": "ChunkOneLastFieldBooleanPolicy desc.", + }, { + "name": "ChunkTwoFirstFieldStringPolicy", + "type": "string", + "schema": { + "type": "string" + }, + "supported_on": ["chrome_os:1-"], + "id": 1816, + "tags": [], + "caption": "ChunkTwoFirstFieldStringPolicy caption", + "desc": "ChunkTwoFirstFieldStringPolicy desc" + }, { + "name": "ChunkTwoLastFieldStringPolicy", + "type": "string", + "schema": { + "type": "string" + }, + "supported_on": ["chrome_os:1-"], + "id": 2615, + "tags": [], + "caption": "ChunkTwoLastFieldStringPolicy caption", + "desc": "ChunkTwoLastFieldStringPolicy desc" + }], + "policy_atomic_group_definitions": [] + } + + def setUp(self): + self.maxDiff = 10000 + self.chrome_major_version = 94 + self.target_platform = 'chrome_os' + self.all_target_platforms = ['win', 'mac', 'linux', 'chromeos', 'fuchsia'] + self.risk_tags = generate_policy_source.RiskTags(self.TEMPLATES_JSON) + self.policies = [ + generate_policy_source.PolicyDetails(policy, self.chrome_major_version, + self.target_platform, + self.risk_tags.GetValidTags()) + for policy in self.TEMPLATES_JSON['policy_definitions'] + ] + self.risk_tags.ComputeMaxTags(self.policies) + + policy_details_set = list(map((lambda x: x.name), self.policies)) + policies_already_in_group = set() + self.policy_atomic_groups = [ + generate_policy_source.PolicyAtomicGroup(group, policy_details_set, + policies_already_in_group) + for group in self.TEMPLATES_JSON['policy_atomic_group_definitions'] + ] + + def testDefaultValueGeneration(self): + """Tests generation of default policy values.""" + # Bools + stmts, expr = generate_policy_source._GenerateDefaultValue(True) + self.assertListEqual([], stmts) + self.assertEqual('base::Value(true)', expr) + stmts, expr = generate_policy_source._GenerateDefaultValue(False) + self.assertListEqual([], stmts) + self.assertEqual('base::Value(false)', expr) + + # Ints + stmts, expr = generate_policy_source._GenerateDefaultValue(33) + self.assertListEqual([], stmts) + self.assertEqual('base::Value(33)', expr) + + # Strings + stmts, expr = generate_policy_source._GenerateDefaultValue('foo') + self.assertListEqual([], stmts) + self.assertEqual('base::Value("foo")', expr) + + # Empty list + stmts, expr = generate_policy_source._GenerateDefaultValue([]) + self.assertListEqual( + ['base::Value default_value(base::Value::Type::LIST);'], stmts) + self.assertEqual('std::move(default_value)', expr) + + # List with values + stmts, expr = generate_policy_source._GenerateDefaultValue([1, '2']) + self.assertListEqual([ + 'base::Value default_value(base::Value::Type::LIST);', + 'default_value.Append(base::Value(1));', + 'default_value.Append(base::Value("2"));' + ], stmts) + self.assertEqual('std::move(default_value)', expr) + + # Recursive lists are not supported. + stmts, expr = generate_policy_source._GenerateDefaultValue([1, []]) + self.assertListEqual([], stmts) + self.assertIsNone(expr) + + # Arbitary types are not supported. + stmts, expr = generate_policy_source._GenerateDefaultValue(object()) + self.assertListEqual([], stmts) + self.assertIsNone(expr) + + def _assertCallsEqual(self, expected_output, call_args_list): + # Convert mocked write calls into actual content that would be written + # to the file. Elements of call_args_list are call objects, which are + # two-tuples of (positional args, keyword args). With call[0] we first + # fetch the positional args, which are an n-tuple, and with call[0][0] + # we get the first positional argument, which is the string that is + # written into the file. + actual_output = ''.join(call[0][0] for call in call_args_list) + + # Strip whitespace from the beginning and end of expected and actual + # output and verify that they are equal. + self.assertEqual(expected_output.strip(), actual_output.strip()) + + def testWriteCloudPolicyProtobuf(self): + is_full_runtime_values = [False, True] + output_path = 'mock_cloud_policy_proto' + + for is_full_runtime in is_full_runtime_values: + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WriteCloudPolicyProtobuf( + self.policies, + self.policy_atomic_groups, + self.target_platform, + f, + self.risk_tags, + is_full_runtime=is_full_runtime) + + full_runtime_comment = '//' if is_full_runtime else '' + full_runtime_suffix = '_full_runtime' if is_full_runtime else '' + + with self.subTest(is_full_runtime=is_full_runtime): + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + + expected_formatted = test_data.EXPECTED_CLOUD_POLICY_PROTOBUF % { + "full_runtime_comment": full_runtime_comment, + "full_runtime_suffix": full_runtime_suffix, + } + + self._assertCallsEqual(expected_formatted, + mocked_file().write.call_args_list) + + def testWriteChromeSettingsProtobuf(self): + is_full_runtime_values = [False, True] + output_path = 'mock_chrome_settings_proto' + + for is_full_runtime in is_full_runtime_values: + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WriteChromeSettingsProtobuf( + self.policies, + self.policy_atomic_groups, + self.target_platform, + f, + self.risk_tags, + is_full_runtime=is_full_runtime) + + full_runtime_comment = '//' if is_full_runtime else '' + full_runtime_suffix = '_full_runtime' if is_full_runtime else '' + + with self.subTest(is_full_runtime=is_full_runtime): + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + + expected_formatted = test_data.EXPECTED_CHROME_SETTINGS_PROTOBUF % { + "full_runtime_comment": full_runtime_comment, + "full_runtime_suffix": full_runtime_suffix, + } + + self._assertCallsEqual(expected_formatted, + mocked_file().write.call_args_list) + + def testWritePolicyProto(self): + output_path = 'mock_write_policy_proto' + + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WritePolicyProto(f, self.policies[0]) + + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + self._assertCallsEqual(test_data.EXPECTED_POLICY_PROTO, + mocked_file().write.call_args_list) + + def testGetMetapoliciesOfType(self): + merge_metapolicies = generate_policy_source._GetMetapoliciesOfType( + self.policies, "merge") + self.assertListEqual(["ExampleBoolMergeMetapolicy"], merge_metapolicies) + self.assertEqual(1, len(merge_metapolicies)) + + precedence_metapolicies = generate_policy_source._GetMetapoliciesOfType( + self.policies, "precedence") + self.assertListEqual(["ExampleBoolPrecedenceMetapolicy"], + precedence_metapolicies) + self.assertEqual(1, len(precedence_metapolicies)) + + invalid_metapolicies = generate_policy_source._GetMetapoliciesOfType( + self.policies, "invalid") + self.assertListEqual([], invalid_metapolicies) + self.assertEqual(0, len(invalid_metapolicies)) + + def testWritePolicyConstantHeader(self): + output_path = 'mock_policy_constants_h' + + for target_platform in self.all_target_platforms: + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WritePolicyConstantHeader( + self.policies, + self.policy_atomic_groups, + target_platform, + f, + self.risk_tags, + ) + with self.subTest(target_platform=target_platform): + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + + if target_platform == 'win': + windows_only_part = test_data.POLICY_CONSTANTS_HEADER_WIN_ONLY_PART + else: + windows_only_part = '' + expected_formatted = test_data.EXPECTED_POLICY_CONSTANTS_HEADER % { + "windows_only_part": windows_only_part, + } + + self._assertCallsEqual(expected_formatted, + mocked_file().write.call_args_list) + + def testWritePolicyConstantSource(self): + output_path = 'mock_policy_constants_cc' + + for target_platform in self.all_target_platforms: + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WritePolicyConstantSource( + self.policies, + self.policy_atomic_groups, + target_platform, + f, + self.risk_tags, + ) + with self.subTest(target_platform=target_platform): + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + + if target_platform == 'win': + windows_only_part = test_data.POLICY_CONSTANTS_SOURCE_WIN_ONLY_PART + else: + windows_only_part = '' + expected_formatted = test_data.EXPECTED_POLICY_CONSTANTS_SOURCE % { + "windows_only_part": windows_only_part, + } + + self._assertCallsEqual(expected_formatted, + mocked_file().write.call_args_list) + + def testWriteChromeOSPolicyConstantsHeader(self): + output_path = 'mock_policy_constants_h' + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WriteChromeOSPolicyConstantsHeader( + self.policies, + self.policy_atomic_groups, + self.target_platform, + f, + self.risk_tags, + ) + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + self._assertCallsEqual(test_data.EXPECTED_CROS_POLICY_CONSTANTS_HEADER, + mocked_file().write.call_args_list) + + def testWriteChromeOSPolicyConstantsSource(self): + output_path = 'mock_policy_constants_cc' + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WriteChromeOSPolicyConstantsSource( + self.policies, + self.policy_atomic_groups, + self.target_platform, + f, + self.risk_tags, + ) + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + self._assertCallsEqual(test_data.EXPECTED_CROS_POLICY_CONSTANTS_SOURCE, + mocked_file().write.call_args_list) + + + def testWriteAppRestrictions(self): + output_path = 'app_restrictions_xml' + with patch('codecs.open', mock_open()) as mocked_file: + with codecs.open(output_path, 'w', encoding='utf-8') as f: + generate_policy_source._WriteAppRestrictions( + self.policies, + self.policy_atomic_groups, + self.target_platform, + f, + self.risk_tags, + ) + mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8') + self._assertCallsEqual(test_data.EXPECTED_APP_RESTRICTIONS_XML, + mocked_file().write.call_args_list) + + + def testChunkNumberAndFieldNumber(self): + test_data = [ + # Last top-level policy + PolicyData(policy_id=1015, chunk_number=0, field_number=1017), + # First policy in chunk 1 + PolicyData(policy_id=1016, chunk_number=1, field_number=1), + # Last policy in chunk 1 + PolicyData(policy_id=1815, chunk_number=1, field_number=800), + # First policy in chunk 2 + PolicyData(policy_id=1816, chunk_number=2, field_number=1), + # Last policy in chunk 2 + PolicyData(policy_id=2615, chunk_number=2, field_number=800), + # First policy in chunk 3 + PolicyData(policy_id=2616, chunk_number=3, field_number=1), + # Last policy in chunk 3 + PolicyData(policy_id=3415, chunk_number=3, field_number=800), + # First policy in chunk 501 + PolicyData(policy_id=401016, chunk_number=501, field_number=1), + # Last policy in chunk 501 + PolicyData(policy_id=401815, chunk_number=501, field_number=800), + # First policy in chunk 502 + PolicyData(policy_id=401816, chunk_number=502, field_number=1), + # Last policy in chunk 502 + PolicyData(policy_id=402615, chunk_number=502, field_number=800), + # First policy in chunk 503 + PolicyData(policy_id=402616, chunk_number=503, field_number=1), + # Last policy in chunk 503 + PolicyData(policy_id=403415, chunk_number=503, field_number=800), + ] + + for policy_data in test_data: + self.assertEqual( + generate_policy_source._ChunkNumber(policy_data.policy_id), + policy_data.chunk_number) + self.assertEqual( + generate_policy_source._FieldNumber(policy_data.policy_id, + policy_data.chunk_number), + policy_data.field_number) + + +if __name__ == '__main__': + unittest.main() |