Home | History | Annotate | Download | only in config
      1 #
      2 # Copyright (C) 2017 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the 'License');
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an 'AS IS' BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 
     17 import os
     18 import sys
     19 
     20 from importlib import import_module
     21 from xml.etree import ElementTree
     22 
     23 
     24 class FuzzerType(object):
     25     """Types of fuzzers."""
     26     FUNC_FUZZER = 0
     27     IFACE_FUZZER = 1
     28 
     29 
     30 class ConfigGen(object):
     31     """Config generator for test/vts-testcase/fuzz.
     32 
     33     Attributes:
     34         _android_build_top: string, equal to environment variable ANDROID_BUILD_TOP.
     35         _project_path: string, path to test/vts-testcase/fuzz.
     36         _template_dir: string, path to directory containig templates.
     37         _utils: test/vts-testcase/hal/script/build/config_gen_utils module.
     38         _vts_spec_parser: tools that generates and parses vts spec with hidl-gen.
     39     """
     40 
     41     def __init__(self):
     42         """ConfigGen constructor. """
     43         self._android_build_top = os.environ.get('ANDROID_BUILD_TOP')
     44         if not self._android_build_top:
     45             print 'Run "lunch" command first.'
     46             sys.exit(1)
     47         self._project_path = os.path.join(self._android_build_top, 'test',
     48                                           'vts-testcase', 'fuzz')
     49         self._template_dir = os.path.join(self._project_path, 'script',
     50                                           'config', 'template')
     51         sys.path.append(
     52             os.path.join(self._android_build_top, 'test', 'vts-testcase', 'hal',
     53                          'script', 'build'))
     54         vts_spec_parser = import_module('vts_spec_parser')
     55         self._utils = import_module('build_rule_gen_utils')
     56         self._vts_spec_parser = vts_spec_parser.VtsSpecParser()
     57 
     58     def _GetPlansFromConfig(self, xml_file_path):
     59         """Gets plan names from a module config.
     60 
     61         Args:
     62             xml_file_path: string, path to the XML file.
     63 
     64         Returns:
     65             list of strings, the plans that the module belongs to.
     66         """
     67         root = ElementTree.parse(xml_file_path).getroot()
     68         plans = [e.attrib["value"] for e in root.iterfind("option") if
     69                  e.get("name", "") == "config-descriptor:metadata" and
     70                  e.get("key", "") == "plan" and
     71                  "value" in e.attrib]
     72         return plans
     73 
     74     def UpdateFuzzerConfigs(self):
     75         """Updates build rules for fuzzers.
     76 
     77         Updates fuzzer configs for each pair of (hal_name, hal_version).
     78         """
     79         config_dir = os.path.join(self._project_path, 'config')
     80         old_config = dict()
     81 
     82         for base_dir, dirs, files, in os.walk(config_dir):
     83             for file_name in files:
     84                 file_path = os.path.join(base_dir, file_name)
     85                 if file_name == 'AndroidTest.xml':
     86                     old_config[file_path] = self._GetPlansFromConfig(file_path)
     87                 if file_name in ('AndroidTest.xml', 'Android.mk'):
     88                     os.remove(file_path)
     89 
     90         self.UpdateFuzzerConfigsForType(FuzzerType.IFACE_FUZZER, old_config)
     91 
     92     def UpdateFuzzerConfigsForType(self, fuzzer_type, old_config):
     93         """Updates build rules for fuzzers.
     94 
     95         Updates fuzzer configs for given fuzzer type.
     96 
     97         Args:
     98             fuzzer_type: FuzzerType, type of fuzzer.
     99             old_config: dict. The key is the path to the old XML. The value is
    100                 the list of the plans the module belongs to.
    101         """
    102         mk_template_path = os.path.join(self._template_dir, 'template.mk')
    103         xml_template_path = os.path.join(self._template_dir, 'template.xml')
    104         with open(mk_template_path) as template_file:
    105             mk_template = str(template_file.read())
    106         with open(xml_template_path) as template_file:
    107             xml_template = str(template_file.read())
    108 
    109         hal_list = self._vts_spec_parser.HalNamesAndVersions()
    110         for hal_name, hal_version in hal_list:
    111             if not self._IsTestable(hal_name, hal_version):
    112                 continue
    113             fuzzer_type_subdir = self._FuzzerTypeUnderscore(fuzzer_type)
    114             config_dir = os.path.join(
    115                 self._project_path, 'config', self._utils.HalNameDir(hal_name),
    116                 self._utils.HalVerDir(hal_version), fuzzer_type_subdir)
    117             mk_file_path = os.path.join(config_dir, 'Android.mk')
    118             xml_file_path = os.path.join(config_dir, 'AndroidTest.xml')
    119 
    120             plan = 'vts-staging-fuzz'
    121             if xml_file_path in old_config:
    122                 old_plans = old_config[xml_file_path]
    123                 if old_plans:
    124                     plan = old_plans[0]
    125                 else:
    126                     print('WARNING: No plan name in %s' % xml_file_path)
    127                 if len(old_plans) > 1:
    128                     print('WARNING: More than one plan name in %s' %
    129                           xml_file_path)
    130 
    131             mk_string = self._FillOutTemplate(
    132                 hal_name, hal_version, fuzzer_type, plan, mk_template)
    133 
    134             xml_string = self._FillOutTemplate(
    135                 hal_name, hal_version, fuzzer_type, plan, xml_template)
    136 
    137             self._utils.WriteBuildRule(mk_file_path, mk_string)
    138             self._utils.WriteBuildRule(xml_file_path, xml_string)
    139 
    140     def _FuzzerTestName(self, hal_name, hal_version, fuzzer_type):
    141         """Returns vts hal fuzzer test module name.
    142 
    143         Args:
    144             hal_name: string, name of the hal, e.g. 'vibrator'.
    145             hal_version: string, version of the hal, e.g '7.4'
    146             fuzzer_type: FuzzerType, type of fuzzer.
    147 
    148         Returns:
    149             string, test module name, e.g. VtsHalVibratorV7_4FuncFuzzer
    150         """
    151         test_name = 'VtsHal'
    152         test_name += ''.join(map(lambda x: x.title(), hal_name.split('.')))
    153         test_name += self._utils.HalVerDir(hal_version)
    154         test_name += self._FuzzerTypeCamel(fuzzer_type)
    155         return test_name
    156 
    157     def _FuzzerTypeUnderscore(self, fuzzer_type):
    158         """Returns vts hal fuzzer type string in underscore case.
    159 
    160         Args:
    161             fuzzer_type: FuzzerType, type of fuzzer.
    162 
    163         Returns:
    164             string, fuzzer type, e.g. "iface_fuzzer"
    165         """
    166         if fuzzer_type == FuzzerType.FUNC_FUZZER:
    167             test_type = 'func_fuzzer'
    168         else:
    169             test_type = 'iface_fuzzer'
    170         return test_type
    171 
    172     def _FuzzerTypeCamel(self, fuzzer_type):
    173         """Returns vts hal fuzzer type string in camel case.
    174 
    175         Args:
    176             fuzzer_type: FuzzerType, type of fuzzer.
    177 
    178         Returns:
    179             string, fuzzer type, e.g. "IfaceFuzzer"
    180         """
    181         if fuzzer_type == FuzzerType.FUNC_FUZZER:
    182             test_type = 'FuncFuzzer'
    183         else:
    184             test_type = 'IfaceFuzzer'
    185         return test_type
    186 
    187     def _FillOutTemplate(self, hal_name, hal_version, fuzzer_type, plan,
    188                          template):
    189         """Returns build rules in string form by filling out given template.
    190 
    191         Args:
    192             hal_name: string, name of the hal, e.g. 'vibrator'.
    193             hal_version: string, version of the hal, e.g '7.4'
    194             fuzzer_type: FuzzerType, type of fuzzer.
    195             plan: string, name of the plan, e.g. 'vts-staging-fuzz'
    196             template: string, build rule template to fill out.
    197 
    198         Returns:
    199             string, complete build rule in string form.
    200         """
    201         config = template
    202         config = config.replace('{TEST_NAME}', self._FuzzerTestName(
    203             hal_name, hal_version, fuzzer_type))
    204         config = config.replace('{HAL_NAME}', hal_name)
    205         config = config.replace('{HAL_VERSION}', hal_version)
    206         config = config.replace('{TEST_TYPE_CAMEL}',
    207                                 self._FuzzerTypeCamel(fuzzer_type))
    208         config = config.replace('{TEST_TYPE_UNDERSCORE}',
    209                                 self._FuzzerTypeUnderscore(fuzzer_type))
    210         config = config.replace('{PLAN}', plan)
    211         return config
    212 
    213     def _IsTestable(self, hal_name, hal_version):
    214         """Returns true iff hal can be tested."""
    215         if 'tests' in hal_name:
    216             return False
    217         return True
    218