1#!/usr/bin/python3 2 3# Copyright (C) 2023 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 17"""Script to automatically populate TEST_MAPPING""" 18 19if __name__ != "__main__": 20 print("This is a script, not a library.") 21 exit(1) 22 23import argparse 24import json 25import os 26import textwrap 27 28from pathlib import Path 29 30# some other things we might consider adding: 31# - support for other classes of tests, besides 'presubmit' 32# - use bpmodify to add tests to 'general-tests' or 'device-tests' automatically 33 34parser = argparse.ArgumentParser( 35 epilog=textwrap.dedent("""For example, 36 `map_tests --dir system/libhidl --tests-in system/libhidl/transport -w` would add the 37 tests in the `transport` subdirectory into system/libhidl/TEST_MAPPING`. In general, 38 it's expected to be used by `map_tests.py -w` in the directory where you want to add 39 tests.""")) 40parser.add_argument("-i", "--module-info", action="store", help="Default is $ANDROID_PRODUCT_OUT/module-info.json. If this is out of date, run `refreshmod`.") 41parser.add_argument("-w", "--write", action="store_true", help="Write over the TEST_MAPPING file.") 42parser.add_argument("-d", "--dir", action="store", help="Directory where TEST_MAPPING file should exist, defaults to current directory.") 43parser.add_argument("-t", "--tests-in", action="store", help="Directory to pull tests from, defaults to test mapping '--dir'") 44parser.add_argument("-p", "--print", action="store", help="Also print the module-info.json entry for this module, or '-' to print everything") 45args = parser.parse_args() 46 47INFO_PATH = args.module_info or (os.environ["ANDROID_PRODUCT_OUT"] + "/module-info.json") 48MAP_DIR = args.dir or os.getcwd() 49TESTS_IN_DIR = args.tests_in or MAP_DIR 50PRINT = args.print 51WRITE = args.write 52del args 53 54MAP_PATH = MAP_DIR + "/TEST_MAPPING" 55TOP = os.environ["ANDROID_BUILD_TOP"] 56 57################################################################################ 58# READ THE CURRENT TEST MAPPING 59################################################################################ 60if os.path.exists(MAP_PATH): 61 with open(MAP_PATH, "r", encoding="utf-8") as f: 62 test_mapping = json.loads("".join(f.readlines())) 63else: 64 test_mapping = {} 65 66################################################################################ 67# READ THE MODULE INFO 68################################################################################ 69with open(INFO_PATH, "r", encoding="utf-8") as module_info_file: 70 info = json.load(module_info_file) 71 72################################################################################ 73# UPDATE TEST MAPPING BASED ON MODULE INFO 74################################################################################ 75tests_dir = os.path.relpath(TESTS_IN_DIR, TOP) 76 77for name,k in info.items(): 78 if PRINT == '-' or name == PRINT: print(name, k) 79 80 # skip 32-bit tests, which show up in module-info.json, but they aren't present 81 # at the atest level 82 if name.endswith("_32"): continue 83 84 is_in_path = any(Path(p).is_relative_to(tests_dir) for p in k['path']) 85 if not is_in_path: continue 86 87 # these are the test_suites that TEST_MAPPING can currently pull tests from 88 is_built = any(ts in k['compatibility_suites'] for ts in ['device-tests', 'general-tests']) 89 if not is_built: continue 90 91 # automatically runs using other infrastructure 92 if k['is_unit_test'] == 'true': continue 93 94 has_test_config = len(k['test_config']) 95 is_native_test = 'NATIVE_TESTS' in k['class'] 96 if not has_test_config and not is_native_test: continue 97 98 if "presubmit" not in test_mapping: test_mapping["presubmit"] = [] 99 100 already_there = any(i["name"] == name for i in test_mapping["presubmit"]) 101 if already_there: continue 102 103 test_mapping["presubmit"] += [{ "name": name }] 104 105out = json.dumps(test_mapping, indent=2) 106 107################################################################################ 108# WRITE THE OUTPUT 109################################################################################ 110if WRITE: 111 with open(MAP_PATH, "w+", encoding="utf-8") as f: 112 f.write(out + "\n") 113else: 114 print(out) 115