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