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
17import os
18import sys
19
20from importlib import import_module
21
22
23class FuzzerType(object):
24    """Types of fuzzers."""
25    FUNC_FUZZER = 0
26    IFACE_FUZZER = 1
27
28
29class ConfigGen(object):
30    """Config generator for test/vts-testcase/fuzz.
31
32    Attributes:
33        _android_build_top: string, equal to environment variable ANDROID_BUILD_TOP.
34        _project_path: string, path to test/vts-testcase/fuzz.
35        _template_dir: string, path to directory containig templates.
36        _utils: test/vts-testcase/hal/script/build/config_gen_utils module.
37        _vts_spec_parser: tools that generates and parses vts spec with hidl-gen.
38    """
39
40    def __init__(self):
41        """ConfigGen constructor. """
42        self._android_build_top = os.environ.get('ANDROID_BUILD_TOP')
43        if not self._android_build_top:
44            print 'Run "lunch" command first.'
45            sys.exit(1)
46        self._project_path = os.path.join(self._android_build_top, 'test',
47                                          'vts-testcase', 'fuzz')
48        self._template_dir = os.path.join(self._project_path, 'script',
49                                          'config', 'template')
50        sys.path.append(
51            os.path.join(self._android_build_top, 'test', 'vts-testcase', 'hal',
52                         'script', 'build'))
53        vts_spec_parser = import_module('vts_spec_parser')
54        self._utils = import_module('build_rule_gen_utils')
55        self._vts_spec_parser = vts_spec_parser.VtsSpecParser()
56
57    def UpdateFuzzerConfigs(self):
58        """Updates build rules for fuzzers.
59
60        Updates fuzzer configs for each pair of (hal_name, hal_version).
61        """
62        config_dir = os.path.join(self._project_path, 'config')
63        self._utils.RemoveFilesInDirIf(
64            config_dir, lambda x: x == 'AndroidTest.xml' or 'Android.mk')
65
66        self.UpdateFuzzerConfigsForType(FuzzerType.FUNC_FUZZER)
67        self.UpdateFuzzerConfigsForType(FuzzerType.IFACE_FUZZER)
68
69    def UpdateFuzzerConfigsForType(self, fuzzer_type):
70        """Updates build rules for fuzzers.
71
72        Updates fuzzer configs for given fuzzer type.
73
74        Args:
75            fuzzer_type: FuzzerType, type of fuzzer.
76        """
77        mk_template_path = os.path.join(self._template_dir, 'template.mk')
78        xml_template_path = os.path.join(self._template_dir, 'template.xml')
79        with open(mk_template_path) as template_file:
80            mk_template = str(template_file.read())
81        with open(xml_template_path) as template_file:
82            xml_template = str(template_file.read())
83
84        hal_list = self._vts_spec_parser.HalNamesAndVersions()
85        for hal_name, hal_version in hal_list:
86            if not self._IsTestable(hal_name, hal_version):
87                continue
88            fuzzer_type_subdir = self._FuzzerTypeUnderscore(fuzzer_type)
89            config_dir = os.path.join(
90                self._project_path, 'config', self._utils.HalNameDir(hal_name),
91                self._utils.HalVerDir(hal_version), fuzzer_type_subdir)
92            mk_file_path = os.path.join(config_dir, 'Android.mk')
93            xml_file_path = os.path.join(config_dir, 'AndroidTest.xml')
94            mk_string = self._FillOutTemplate(hal_name, hal_version,
95                                              fuzzer_type, mk_template)
96
97            xml_string = self._FillOutTemplate(hal_name, hal_version,
98                                               fuzzer_type, xml_template)
99
100            self._utils.WriteBuildRule(mk_file_path, mk_string)
101            self._utils.WriteBuildRule(xml_file_path, xml_string)
102
103    def _FuzzerTestName(self, hal_name, hal_version, fuzzer_type):
104        """Returns vts hal fuzzer test module name.
105
106        Args:
107            hal_name: string, name of the hal, e.g. 'vibrator'.
108            hal_version: string, version of the hal, e.g '7.4'
109            fuzzer_type: FuzzerType, type of fuzzer.
110
111        Returns:
112            string, test module name, e.g. VtsHalVibratorV7_4FuncFuzzer
113        """
114        test_name = 'VtsHal'
115        test_name += ''.join(map(lambda x: x.title(), hal_name.split('.')))
116        test_name += self._utils.HalVerDir(hal_version)
117        test_name += self._FuzzerTypeCamel(fuzzer_type)
118        return test_name
119
120    def _FuzzerTypeUnderscore(self, fuzzer_type):
121        """Returns vts hal fuzzer type string in underscore case.
122
123        Args:
124            fuzzer_type: FuzzerType, type of fuzzer.
125
126        Returns:
127            string, fuzzer type, e.g. "iface_fuzzer"
128        """
129        if fuzzer_type == FuzzerType.FUNC_FUZZER:
130            test_type = 'func_fuzzer'
131        else:
132            test_type = 'iface_fuzzer'
133        return test_type
134
135    def _FuzzerTypeCamel(self, fuzzer_type):
136        """Returns vts hal fuzzer type string in camel case.
137
138        Args:
139            fuzzer_type: FuzzerType, type of fuzzer.
140
141        Returns:
142            string, fuzzer type, e.g. "IfaceFuzzer"
143        """
144        if fuzzer_type == FuzzerType.FUNC_FUZZER:
145            test_type = 'FuncFuzzer'
146        else:
147            test_type = 'IfaceFuzzer'
148        return test_type
149
150    def _FillOutTemplate(self, hal_name, hal_version, fuzzer_type, template):
151        """Returns build rules in string form by filling out given template.
152
153        Args:
154            hal_name: string, name of the hal, e.g. 'vibrator'.
155            hal_version: string, version of the hal, e.g '7.4'
156            fuzzer_type: FuzzerType, type of fuzzer.
157            template: string, build rule template to fill out.
158
159        Returns:
160            string, complete build rule in string form.
161        """
162        config = template
163        config = config.replace('{TEST_NAME}', self._FuzzerTestName(
164            hal_name, hal_version, fuzzer_type))
165        config = config.replace('{HAL_NAME}', hal_name)
166        config = config.replace('{HAL_VERSION}', hal_version)
167        config = config.replace('{TEST_TYPE_CAMEL}',
168                                self._FuzzerTypeCamel(fuzzer_type))
169        config = config.replace('{TEST_TYPE_UNDERSCORE}',
170                                self._FuzzerTypeUnderscore(fuzzer_type))
171        return config
172
173    def _IsTestable(self, hal_name, hal_version):
174        """Returns true iff hal can be tested."""
175        if 'tests' in hal_name:
176            return False
177        return True
178