• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import difflib
18import filecmp
19import getopt
20import logging
21import os
22import shutil
23import subprocess
24import sys
25import unittest
26
27from vts.utils.python.common import cmd_utils
28
29
30class VtscTester(unittest.TestCase):
31    """Integration test runner for vtsc in generating the driver/profiler code.
32
33    Runs vtsc with specified mode on a bunch of files and compares the output
34    results with canonical ones. Exit code is 0 iff all tests pass.
35    Note: need to run the script from the source root to preserve the correct
36          path.
37
38    Usage:
39        python test_vtsc.py path_to_vtsc canonical_dir output_dir
40
41    example:
42        python test/vts/compilation_tools/vtsc/test/test_vtsc.py vtsc
43        test/vts/compilation_tools/vtsc/test/golden/ temp_output
44
45    Attributes:
46        _hidl_gen_path: the path to run hidl-gen
47        _vtsc_path: the path to run vtsc.
48        _canonical_dir: root directory contains canonical files for comparison.
49        _output_dir: root directory that stores all output files.
50        _errors: number of errors generates during the test.
51        _temp_dir: temp dir to store the .vts file generated by hidl-gen.
52    """
53
54    def __init__(self, testName, hidl_gen_path, vtsc_path, canonical_dir,
55                 output_dir, temp_dir):
56        super(VtscTester, self).__init__(testName)
57        self._hidl_gen_path = hidl_gen_path
58        self._vtsc_path = vtsc_path
59        self._canonical_dir = canonical_dir
60        self._output_dir = output_dir
61        self._errors = 0
62        self._temp_dir = temp_dir
63
64    def setUp(self):
65        """Removes output dir to prevent interference from previous runs."""
66        self.RemoveOutputDir()
67
68    def tearDown(self):
69        """If successful, removes the output dir for clean-up."""
70        if self._errors == 0:
71            self.RemoveOutputDir()
72
73    def testAll(self):
74        """Run all tests. """
75        self.TestDriver()
76        self.TestProfiler()
77        self.TestFuzzer()
78        self.assertEqual(self._errors, 0)
79
80    def TestDriver(self):
81        """Run tests for DRIVER mode. """
82        logging.info("Running TestDriver test case.")
83        # Tests for Hidl Hals.
84        for package_path, component_names in zip(
85            ["android.hardware.nfc@1.0",
86             "android.hardware.tests.bar@1.0",
87             "android.hardware.tests.msgq@1.0",
88             "android.hardware.tests.memory@1.0"],
89            [["Nfc", "NfcClientCallback", "types"],
90             ["Bar"], ["TestMsgQ"], ["MemoryTest"]]):
91            self.GenerateVtsFile(package_path)
92            for component_name in component_names:
93                self.RunTest(
94                    "DRIVER",
95                    os.path.join(self._temp_dir, component_name + ".vts"),
96                    "%s.vts.h" % component_name,
97                    header_file_name="%s.vts.h" % component_name,
98                    file_type="HEADER")
99                self.RunTest(
100                    "DRIVER",
101                    os.path.join(self._temp_dir, component_name + ".vts"),
102                    "%s.driver.cpp" % component_name,
103                    file_type="SOURCE")
104        # Tests for conventional Hals.
105        for package_path, component_name in zip(
106            ["camera/2.1", "bluetooth/1.0", "bluetooth/1.0", "wifi/1.0"], [
107                "CameraHalV2", "BluetoothHalV1",
108                "BluetoothHalV1bt_interface_t", "WifiHalV1"
109            ]):
110            self.RunTest("DRIVER",
111                         "test/vts/specification/hal/conventional/%s/%s.vts" %
112                         (package_path,
113                          component_name), "%s.driver.cpp" % component_name)
114        # Tests for shared libraries.
115        for component_name in ["libcV1"]:
116            self.RunTest("DRIVER",
117                         "test/vts/specification/lib/ndk/bionic/1.0/%s.vts" %
118                         component_name, "%s.driver.cpp" % component_name)
119
120    def TestProfiler(self):
121        """Run tests for PROFILER mode. """
122        logging.info("Running TestProfiler test case.")
123        #self.GenerateVtsFile("android.hardware.nfc@1.0")
124        for package_path, component_names in zip(
125            ["android.hardware.nfc@1.0",
126             "android.hardware.tests.bar@1.0",
127             "android.hardware.tests.msgq@1.0",
128             "android.hardware.tests.memory@1.0"],
129            [["Nfc", "NfcClientCallback", "types"],
130             ["Bar"], ["TestMsgQ"], ["MemoryTest"]]):
131            self.GenerateVtsFile(package_path)
132            for component_name in component_names:
133                self.RunTest(
134                    "PROFILER",
135                    os.path.join(self._temp_dir, component_name + ".vts"),
136                    "%s.vts.h" % component_name,
137                    header_file_name="%s.vts.h" % component_name,
138                    file_type="HEADER")
139                self.RunTest(
140                    "PROFILER",
141                    os.path.join(self._temp_dir, component_name + ".vts"),
142                    "%s.profiler.cpp" % component_name,
143                    file_type="SOURCE")
144
145    def TestFuzzer(self):
146        """Run tests for Fuzzer mode. """
147        logging.info("Running TestProfiler test case.")
148        self.GenerateVtsFile("android.hardware.renderscript@1.0")
149        for component_name in ["Context", "Device", "types"]:
150            self.RunTest(
151                "FUZZER",
152                os.path.join(self._temp_dir, component_name + ".vts"),
153                "%s.fuzzer.cpp" % component_name,
154                file_type="SOURCE")
155
156    def RunFuzzerTest(self, mode, vts_file_path, source_file_name):
157        vtsc_cmd = [
158            self._vtsc_path, "-m" + mode, vts_file_path,
159            os.path.join(self._output_dir, mode),
160            os.path.join(self._output_dir, mode, "")
161        ]
162        return_code = cmd_utils.RunCommand(vtsc_cmd)
163
164        canonical_source_file = os.path.join(self._canonical_dir, mode,
165                                             source_file_name)
166        output_source_file = os.path.join(self._output_dir, mode,
167                                          source_file_name)
168        self.CompareOutputFile(output_source_file, canonical_source_file)
169
170    def GenerateVtsFile(self, hal_package_name):
171        """Run hidl-gen to generate the .vts files for the give hal package.
172
173        Args:
174            hal_package_name: name of hal package e.g. android.hardware.nfc@1.0
175        """
176        hidl_gen_cmd = [
177            self._hidl_gen_path, "-o" + self._temp_dir, "-Lvts",
178            "-randroid.hardware:hardware/interfaces",
179            "-randroid.hidl:system/libhidl/transport", hal_package_name
180        ]
181        return_code = cmd_utils.RunCommand(hidl_gen_cmd)
182        if (return_code != 0):
183            self.Error("Fail to execute command: %s" % hidl_gen_cmd)
184        [hal_name, hal_version] = hal_package_name.split("@")
185        output_dir = os.path.join(self._temp_dir,
186                                  hal_name.replace(".", "/"), hal_version)
187        for file in os.listdir(output_dir):
188            if file.endswith(".vts"):
189                os.rename(
190                    os.path.join(output_dir, file),
191                    os.path.join(self._temp_dir, file))
192
193    def RunTest(self,
194                mode,
195                vts_file_path,
196                output_file_name,
197                header_file_name="",
198                file_type="BOTH"):
199        """Run vtsc with given mode for the give vts file and compare the
200           output results.
201
202        Args:
203            mode: the vtsc mode for generated code. e.g. DRIVER / PROFILER.
204            vts_file_path: path of the input vts file.
205            source_file_name: name of the generated source file.
206            file_type: type of file e.g. HEADER / SOURCE / BOTH.
207        """
208        if (file_type == "BOTH"):
209            vtsc_cmd = [
210                self._vtsc_path, "-m" + mode, vts_file_path,
211                os.path.join(self._output_dir, mode),
212                os.path.join(self._output_dir, mode, output_file_name)
213            ]
214        else:
215            vtsc_cmd = [
216                self._vtsc_path, "-m" + mode, "-t" + file_type, vts_file_path,
217                os.path.join(self._output_dir, mode, output_file_name)
218            ]
219        return_code = cmd_utils.RunCommand(vtsc_cmd)
220        if (return_code != 0):
221            self.Error("Fail to execute command: %s" % vtsc_cmd)
222
223        if (file_type == "HEADER" or file_type == "BOTH"):
224            if not header_file_name:
225                header_file_name = vts_file_path + ".h"
226            canonical_header_file = os.path.join(self._canonical_dir, mode,
227                                                 header_file_name)
228            output_header_file = os.path.join(self._output_dir, mode,
229                                              header_file_name)
230            self.CompareOutputFile(output_header_file, canonical_header_file)
231        elif (file_type == "SOURCE" or file_type == "BOTH"):
232            canonical_source_file = os.path.join(self._canonical_dir, mode,
233                                                 output_file_name)
234            output_source_file = os.path.join(self._output_dir, mode,
235                                              output_file_name)
236            self.CompareOutputFile(output_source_file, canonical_source_file)
237        else:
238            self.Error("No such file_type: %s" % file_type)
239
240    def CompareOutputFile(self, output_file, canonical_file):
241        """Compares a given file and the corresponding one under canonical_dir.
242
243        Args:
244            canonical_file: name of the canonical file.
245            output_file: name of the output file.
246        """
247        if not os.path.isfile(canonical_file):
248            self.Error("Generated unexpected file: %s (for %s)" %
249                       (output_file, canonical_file))
250        else:
251            if not filecmp.cmp(output_file, canonical_file):
252                self.Error(
253                    "output file: %s does not match the canonical_file: "
254                    "%s" % (output_file, canonical_file))
255                self.PrintDiffFiles(output_file, canonical_file)
256
257    def PrintDiffFiles(self, output_file, canonical_file):
258        with open(output_file, 'r') as file1:
259            with open(canonical_file, 'r') as file2:
260                diff = difflib.unified_diff(
261                    file1.readlines(),
262                    file2.readlines(),
263                    fromfile=output_file,
264                    tofile=canonical_file)
265        for line in diff:
266            logging.error(line)
267
268    def Error(self, string):
269        """Prints an error message and increments error count."""
270        logging.error(string)
271        self._errors += 1
272
273    def RemoveOutputDir(self):
274        """Remove the output_dir if it exists."""
275        if os.path.exists(self._output_dir):
276            logging.info("rm -rf %s", self._output_dir)
277            shutil.rmtree(self._output_dir)
278        if os.path.exists(self._temp_dir):
279            shutil.rmtree(self._temp_dir)
280
281
282if __name__ == "__main__":
283    # Default values of the input parameter, could be overridden by command.
284    vtsc_path = "vtsc"
285    canonical_dir = "test/vts/compilation_tools/vtsc/test/golden/"
286    output_dir = "test/vts/compilation_tools/vtsc/test/temp_coutput/"
287    # Parse the arguments and set the provided value for
288    # hidl-gen/vtsc_path/canonical_dar/output_dir.
289    try:
290        opts, _ = getopt.getopt(sys.argv[1:], "h:p:c:o:t:")
291    except getopt.GetoptError, err:
292        print "Usage: python test_vtsc.py [-h hidl_gen_path] [-p vtsc_path] " \
293              "[-c canonical_dir] [-o output_dir] [-t temp_dir]"
294        sys.exit(1)
295    for opt, val in opts:
296        if opt == "-h":
297            hidl_gen_path = val
298        elif opt == "-p":
299            vtsc_path = val
300        elif opt == "-c":
301            canonical_dir = val
302        elif opt == "-o":
303            output_dir = val
304        elif opt == "-t":
305            temp_dir = val
306        else:
307            print "unhandled option %s" % (opt, )
308            sys.exit(1)
309
310    suite = unittest.TestSuite()
311    suite.addTest(
312        VtscTester('testAll', hidl_gen_path, vtsc_path, canonical_dir,
313                   output_dir, temp_dir))
314    result = unittest.TextTestRunner(verbosity=2).run(suite)
315    if not result.wasSuccessful():
316        sys.exit(-1)
317