Home | History | Annotate | Download | only in resources
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 # If this presubmit check fails or misbehaves, please complain to
      6 # mnissler (at] chromium.org, pastarmovj (at] chromium.org or joaodasilva (at] chromium.org.
      7 
      8 import itertools
      9 import sys
     10 import xml.dom.minidom
     11 
     12 def _GetPolicyTemplates(template_path):
     13   # Read list of policies in the template. eval() is used instead of a JSON
     14   # parser because policy_templates.json is not quite JSON, and uses some
     15   # python features such as #-comments and '''strings'''. policy_templates.json
     16   # is actually maintained as a python dictionary.
     17   with open(template_path) as f:
     18     template_data = eval(f.read(), {})
     19   policies = ( policy
     20                for policy in template_data['policy_definitions']
     21                if policy['type'] != 'group' )
     22   groups = ( policy['policies']
     23              for policy in template_data['policy_definitions']
     24              if policy['type'] == 'group' )
     25   subpolicies = ( policy for group in groups for policy in group )
     26   return list(itertools.chain(policies, subpolicies))
     27 
     28 def _CheckPolicyTemplatesSyntax(input_api, output_api):
     29   local_path = input_api.PresubmitLocalPath()
     30   filepath = input_api.os_path.join(local_path, 'policy_templates.json')
     31   if any(f.AbsoluteLocalPath() == filepath
     32          for f in input_api.AffectedFiles()):
     33     old_sys_path = sys.path
     34     try:
     35       tools_path = input_api.os_path.normpath(
     36           input_api.os_path.join(local_path, input_api.os_path.pardir, 'tools'))
     37       sys.path = [ tools_path ] + sys.path
     38       # Optimization: only load this when it's needed.
     39       import syntax_check_policy_template_json
     40       checker = syntax_check_policy_template_json.PolicyTemplateChecker()
     41       if checker.Run([], filepath) > 0:
     42         return [output_api.PresubmitError('Syntax error(s) in file:',
     43                                           [filepath])]
     44     finally:
     45       sys.path = old_sys_path
     46   return []
     47 
     48 
     49 def _CheckPolicyTestCases(input_api, output_api, policies):
     50   # Read list of policies in chrome/test/data/policy/policy_test_cases.json.
     51   root = input_api.change.RepositoryRoot()
     52   policy_test_cases_file = input_api.os_path.join(
     53       root, 'chrome', 'test', 'data', 'policy', 'policy_test_cases.json')
     54   test_names = input_api.json.load(open(policy_test_cases_file)).keys()
     55   tested_policies = frozenset(name.partition('.')[0]
     56                               for name in test_names
     57                               if name[:2] != '--')
     58   policy_names = frozenset(policy['name'] for policy in policies)
     59 
     60   # Finally check if any policies are missing.
     61   missing = policy_names - tested_policies
     62   extra = tested_policies - policy_names
     63   error_missing = ('Policy \'%s\' was added to policy_templates.json but not '
     64                    'to src/chrome/test/data/policy/policy_test_cases.json. '
     65                    'Please update both files.')
     66   error_extra = ('Policy \'%s\' is tested by '
     67                  'src/chrome/test/data/policy/policy_test_cases.json but is not'
     68                  ' defined in policy_templates.json. Please update both files.')
     69   results = []
     70   for policy in missing:
     71     results.append(output_api.PresubmitError(error_missing % policy))
     72   for policy in extra:
     73     results.append(output_api.PresubmitError(error_extra % policy))
     74   return results
     75 
     76 
     77 def _CheckPolicyHistograms(input_api, output_api, policies):
     78   root = input_api.change.RepositoryRoot()
     79   histograms = input_api.os_path.join(
     80       root, 'tools', 'metrics', 'histograms', 'histograms.xml')
     81   with open(histograms) as f:
     82     tree = xml.dom.minidom.parseString(f.read())
     83   enums = (tree.getElementsByTagName('histogram-configuration')[0]
     84                .getElementsByTagName('enums')[0]
     85                .getElementsByTagName('enum'))
     86   policy_enum = [e for e in enums
     87                  if e.getAttribute('name') == 'EnterprisePolicies'][0]
     88   policy_ids = frozenset([int(e.getAttribute('value'))
     89                           for e in policy_enum.getElementsByTagName('int')])
     90 
     91   error_missing = ('Policy \'%s\' was added to policy_templates.json but not '
     92                    'to src/tools/metrics/histograms/histograms.xml. '
     93                    'Please update both files.')
     94   results = []
     95   for policy in policies:
     96     if policy['id'] not in policy_ids:
     97       results.append(output_api.PresubmitError(error_missing % policy['name']))
     98   return results
     99 
    100 
    101 def _CommonChecks(input_api, output_api):
    102   results = []
    103   results.extend(_CheckPolicyTemplatesSyntax(input_api, output_api))
    104 
    105   os_path = input_api.os_path
    106   local_path = input_api.PresubmitLocalPath()
    107   template_path = os_path.join(local_path, 'policy_templates.json')
    108   affected_files = input_api.AffectedFiles()
    109   if any(f.AbsoluteLocalPath() == template_path for f in affected_files):
    110     try:
    111       policies = _GetPolicyTemplates(template_path)
    112     except:
    113       results.append(output_api.PresubmitError('Invalid Python/JSON syntax.'))
    114       return results
    115     results.extend(_CheckPolicyTestCases(input_api, output_api, policies))
    116     results.extend(_CheckPolicyHistograms(input_api, output_api, policies))
    117 
    118   return results
    119 
    120 
    121 def CheckChangeOnUpload(input_api, output_api):
    122   return _CommonChecks(input_api, output_api)
    123 
    124 
    125 def CheckChangeOnCommit(input_api, output_api):
    126   return _CommonChecks(input_api, output_api)
    127