| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (C) 2020 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 | """Add tests to TEST_MAPPING. Include tests for reverse dependencies.""" |
| 17 | import json |
| 18 | import os |
| 19 | import platform |
| 20 | import subprocess |
| 21 | import sys |
| 22 | |
| Joel Galenson | a0d4c5e | 2021-04-06 09:36:47 -0700 | [diff] [blame^] | 23 | test_options = { |
| 24 | "ring_device_test_tests_digest_tests": [{"test-timeout": "600000"}], |
| 25 | "ring_device_test_src_lib": [{"test-timeout": "100000"}], |
| 26 | } |
| Jeff Vander Stoep | 0b0e24f | 2021-01-24 20:50:26 +0100 | [diff] [blame] | 27 | test_exclude = [ |
| 28 | "aidl_test_rust_client", |
| 29 | "aidl_test_rust_service" |
| 30 | ] |
| 31 | exclude_paths = [ |
| 32 | "//external/adhd", |
| 33 | "//external/crosvm", |
| 34 | "//external/libchromeos-rs", |
| 35 | "//external/vm_tools" |
| 36 | ] |
| 37 | |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 38 | class Env(object): |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 39 | def __init__(self, path): |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 40 | try: |
| 41 | self.ANDROID_BUILD_TOP = os.environ['ANDROID_BUILD_TOP'] |
| 42 | except: |
| 43 | sys.exit('ERROR: this script must be run from an Android tree.') |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 44 | if path == None: |
| 45 | self.cwd = os.getcwd() |
| 46 | else: |
| 47 | self.cwd = path |
| 48 | try: |
| 49 | self.cwd_relative = self.cwd.split(self.ANDROID_BUILD_TOP)[1] |
| Jeff Vander Stoep | 82ee11a | 2021-02-04 11:39:25 +0100 | [diff] [blame] | 50 | self.setup = True |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 51 | except: |
| Jeff Vander Stoep | 82ee11a | 2021-02-04 11:39:25 +0100 | [diff] [blame] | 52 | # Mark setup as failed if a path to a rust crate is not provided. |
| 53 | self.setup = False |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 54 | |
| 55 | class Bazel(object): |
| 56 | # set up the Bazel queryview |
| 57 | def __init__(self, env): |
| 58 | os.chdir(env.ANDROID_BUILD_TOP) |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 59 | print("Building Bazel Queryview. This can take a couple of minutes...") |
| 60 | cmd = "./build/soong/soong_ui.bash --build-mode --all-modules --dir=. queryview" |
| 61 | try: |
| 62 | out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) |
| Jeff Vander Stoep | 82ee11a | 2021-02-04 11:39:25 +0100 | [diff] [blame] | 63 | self.setup = True |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 64 | except subprocess.CalledProcessError as e: |
| 65 | print("Error: Unable to update TEST_MAPPING due to the following build error:") |
| Jeff Vander Stoep | 82ee11a | 2021-02-04 11:39:25 +0100 | [diff] [blame] | 66 | print(e.output) |
| 67 | # Mark setup as failed if the Bazel queryview fails to build. |
| 68 | self.setup = False |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 69 | os.chdir(env.cwd) |
| 70 | |
| 71 | def path(self): |
| 72 | # Only tested on Linux. |
| 73 | if platform.system() != 'Linux': |
| 74 | sys.exit('ERROR: this script has only been tested on Linux.') |
| 75 | return "/usr/bin/bazel" |
| 76 | |
| 77 | # Return all modules for a given path. |
| 78 | def query_modules(self, path): |
| 79 | with open(os.devnull, 'wb') as DEVNULL: |
| 80 | cmd = self.path() + " query --config=queryview /" + path + ":all" |
| 81 | out = subprocess.check_output(cmd, shell=True, stderr=DEVNULL, text=True).strip().split("\n") |
| 82 | modules = set() |
| 83 | for line in out: |
| 84 | # speed up by excluding unused modules. |
| 85 | if "windows_x86" in line: |
| 86 | continue |
| 87 | modules.add(line) |
| 88 | return modules |
| 89 | |
| 90 | # Return all reverse dependencies for a single module. |
| 91 | def query_rdeps(self, module): |
| 92 | with open(os.devnull, 'wb') as DEVNULL: |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 93 | cmd = (self.path() + " query --config=queryview \'rdeps(//..., " + |
| 94 | module + ")\' --output=label_kind") |
| 95 | out = (subprocess.check_output(cmd, shell=True, stderr=DEVNULL, text=True) |
| 96 | .strip().split("\n")) |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 97 | if '' in out: |
| 98 | out.remove('') |
| 99 | return out |
| 100 | |
| Jeff Vander Stoep | 0b0e24f | 2021-01-24 20:50:26 +0100 | [diff] [blame] | 101 | def exclude_module(self, module): |
| 102 | for path in exclude_paths: |
| 103 | if module.startswith(path): |
| 104 | return True |
| 105 | return False |
| 106 | |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 107 | # Return all reverse dependency tests for modules in this package. |
| 108 | def query_rdep_tests(self, modules): |
| 109 | rdep_tests = set() |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 110 | for module in modules: |
| 111 | for rdep in self.query_rdeps(module): |
| Jeff Vander Stoep | 0b0e24f | 2021-01-24 20:50:26 +0100 | [diff] [blame] | 112 | rule_type, tmp, mod = rdep.split(" ") |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 113 | if rule_type == "rust_test_" or rule_type == "rust_test": |
| Jeff Vander Stoep | 0b0e24f | 2021-01-24 20:50:26 +0100 | [diff] [blame] | 114 | if self.exclude_module(mod) == False: |
| 115 | rdep_tests.add(mod.split(":")[1].split("--")[0]) |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 116 | return rdep_tests |
| 117 | |
| 118 | |
| 119 | class Crate(object): |
| 120 | def __init__(self, path, bazel): |
| 121 | self.modules = bazel.query_modules(path) |
| 122 | self.rdep_tests = bazel.query_rdep_tests(self.modules) |
| 123 | |
| 124 | def get_rdep_tests(self): |
| 125 | return self.rdep_tests |
| 126 | |
| 127 | |
| 128 | class TestMapping(object): |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 129 | def __init__(self, path): |
| 130 | self.env = Env(path) |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 131 | self.bazel = Bazel(self.env) |
| 132 | |
| 133 | def create_test_mapping(self, path): |
| Jeff Vander Stoep | 82ee11a | 2021-02-04 11:39:25 +0100 | [diff] [blame] | 134 | if self.env.setup == False or self.bazel.setup == False: |
| 135 | return |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 136 | tests = self.get_tests(path) |
| 137 | if not bool(tests): |
| 138 | return |
| 139 | test_mapping = self.tests_to_mapping(tests) |
| 140 | self.write_test_mapping(test_mapping) |
| 141 | |
| 142 | def get_tests(self, path): |
| 143 | # for each path collect local Rust modules. |
| 144 | if path is not None and path != "": |
| 145 | return Crate(self.env.cwd_relative + "/" + path, self.bazel).get_rdep_tests() |
| 146 | else: |
| 147 | return Crate(self.env.cwd_relative, self.bazel).get_rdep_tests() |
| 148 | |
| 149 | def tests_to_mapping(self, tests): |
| 150 | test_mapping = {"presubmit": []} |
| 151 | for test in tests: |
| Jeff Vander Stoep | 0b0e24f | 2021-01-24 20:50:26 +0100 | [diff] [blame] | 152 | if test in test_exclude: |
| 153 | continue |
| 154 | if test in test_options: |
| 155 | test_mapping["presubmit"].append({"name": test, "options": test_options[test]}) |
| 156 | else: |
| 157 | test_mapping["presubmit"].append({"name": test}) |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 158 | return test_mapping |
| 159 | |
| 160 | def write_test_mapping(self, test_mapping): |
| 161 | with open("TEST_MAPPING", "w") as json_file: |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 162 | json_file.write("// Generated by update_crate_tests.py for tests that depend on this crate.\n") |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 163 | json.dump(test_mapping, json_file, indent=2, separators=(',', ': '), sort_keys=True) |
| 164 | json_file.write("\n") |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 165 | print("TEST_MAPPING successfully updated!") |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 166 | |
| 167 | def main(): |
| Jeff Vander Stoep | 1b24dc3 | 2021-02-03 18:52:42 +0100 | [diff] [blame] | 168 | if len(sys.argv) == 2: |
| 169 | path = sys.argv[1] |
| 170 | else: |
| 171 | path = None |
| 172 | TestMapping(path).create_test_mapping(None) |
| Jeff Vander Stoep | cec8bac | 2021-01-15 14:15:37 +0100 | [diff] [blame] | 173 | |
| 174 | if __name__ == '__main__': |
| 175 | main() |