diff options
author | Yifan Hong <elsk@google.com> | 2021-03-15 15:01:01 -0700 |
---|---|---|
committer | Yifan Hong <elsk@google.com> | 2021-03-15 17:23:20 -0700 |
commit | 0077a9d530776326f0d30c62063ea1054dab53f3 (patch) | |
tree | 1f4cf79f6f2bd3b3ae54af30a1a01cc53baa6b44 /scripts/list_hal_vts.py | |
parent | 8548f574eec2fd65aa56c5fbbcb01b78dfb07cc9 (diff) |
Add script to get prelim HAL VTS coverage.
See help message for example usage.
Test: doctest
Test: run with and without --csv
Bug: 182810953
Change-Id: I6a4be9b543622618e2c594ba08a75534c60f3136
Diffstat (limited to 'scripts/list_hal_vts.py')
-rwxr-xr-x | scripts/list_hal_vts.py | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/scripts/list_hal_vts.py b/scripts/list_hal_vts.py new file mode 100755 index 0000000000..1fb51a5c9e --- /dev/null +++ b/scripts/list_hal_vts.py @@ -0,0 +1,143 @@ +#!/usr/bin/python3 + +""" +List VTS tests for each HAL by parsing module-info.json. + +Example usage: + + # First, build modules-info.json + m -j "${ANDROID_PRODUCT_OUT#$ANDROID_BUILD_TOP/}/module-info.json" + + # List with pretty-printed JSON. *IDL packages without a VTS module will show up + # as keys with empty lists. + ./list_hals_vts.py | python3 -m json.tool + + # List with CSV. *IDL packages without a VTS module will show up as a line with + # empty value in the VTS module column. + ./list_hals_vts.py --csv +""" + +import argparse +import collections +import csv +import io +import json +import os +import logging +import pathlib +import re +import sys + +PATH_PACKAGE_PATTERN = re.compile( + r'^hardware/interfaces/(?P<path>(?:\w+/)*?)(?:aidl|(?P<version>\d+\.\d+))/.*') + + +class CriticalHandler(logging.StreamHandler): + def emit(self, record): + super(CriticalHandler, self).emit(record) + if record.levelno >= logging.CRITICAL: + sys.exit(1) + + +logger = logging.getLogger(__name__) +logger.addHandler(CriticalHandler()) + + +def default_json(): + out = os.environ.get('ANDROID_PRODUCT_OUT') + if not out: return None + return os.path.join(out, 'module-info.json') + + +def infer_package(path): + """ + Infer package from a relative path from build top where a VTS module lives. + + :param path: a path like 'hardware/interfaces/vibrator/aidl/vts' + :return: The inferred *IDL package, e.g. 'android.hardware.vibrator' + + >>> infer_package('hardware/interfaces/automotive/sv/1.0/vts/functional') + 'android.hardware.automotive.sv@1.0' + >>> infer_package('hardware/interfaces/vibrator/aidl/vts') + 'android.hardware.vibrator' + """ + mo = re.match(PATH_PACKAGE_PATTERN, path) + if not mo: return None + package = 'android.hardware.' + ('.'.join(pathlib.Path(mo.group('path')).parts)) + if mo.group('version'): + package += '@' + mo.group('version') + return package + + +def load_modules_info(json_file): + """ + :param json_file: The path to modules-info.json + :return: a dictionary, where the keys are inferred *IDL package names, and + values are a list of VTS modules with that inferred package name. + """ + with open(json_file) as fp: + root = json.load(fp) + ret = collections.defaultdict(list) + for module_name, module_info in root.items(): + if 'vts' not in module_info.get('compatibility_suites', []): + continue + for path in module_info.get('path', []): + inferred_package = infer_package(path) + if not inferred_package: + continue + ret[inferred_package].append(module_name) + return ret + + +def add_missing_idl(vts_modules): + top = os.environ.get("ANDROID_BUILD_TOP") + interfaces = None + if top: + interfaces = os.path.join(top, "hardware", "interfaces") + else: + logger.warning("Missing ANDROID_BUILD_TOP") + interfaces = "hardware/interfaces" + if not os.path.isdir(interfaces): + logger.error("Not adding missing *IDL modules because missing hardware/interfaces dir") + return + assert not interfaces.endswith(os.path.sep) + for root, dirs, files in os.walk(interfaces): + for dir in dirs: + full_dir = os.path.join(root, dir) + assert full_dir.startswith(interfaces) + top_rel_dir = os.path.join('hardware', 'interfaces', full_dir[len(interfaces) + 1:]) + inferred_package = infer_package(top_rel_dir) + if inferred_package is None: + continue + if inferred_package not in vts_modules: + vts_modules[inferred_package] = [] + + +def main(): + parser = argparse.ArgumentParser(__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('json', metavar='module-info.json', default=default_json(), nargs='?') + parser.add_argument('--csv', action='store_true', help='Print CSV. If not specified print JSON.') + args = parser.parse_args() + if not args.json: + logger.critical('No module-info.json is specified or found.') + vts_modules = load_modules_info(args.json) + add_missing_idl(vts_modules) + + if args.csv: + out = io.StringIO() + writer = csv.writer(out, ) + writer.writerow(["package", "vts_module"]) + for package, modules in vts_modules.items(): + if not modules: + writer.writerow([package, ""]) + for module in modules: + writer.writerow([package, module]) + result = out.getvalue() + else: + result = json.dumps(vts_modules) + + print(result) + + +if __name__ == '__main__': + main() |