blob: 46e94a8ab2cd1fe54b6e1081879e2af9dcf2108a [file] [log] [blame]
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +01001#!/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."""
17import json
18import os
19import platform
20import subprocess
21import sys
22
Joel Galensona0d4c5e2021-04-06 09:36:47 -070023test_options = {
24 "ring_device_test_tests_digest_tests": [{"test-timeout": "600000"}],
25 "ring_device_test_src_lib": [{"test-timeout": "100000"}],
26}
Jeff Vander Stoep0b0e24f2021-01-24 20:50:26 +010027test_exclude = [
28 "aidl_test_rust_client",
29 "aidl_test_rust_service"
30 ]
31exclude_paths = [
32 "//external/adhd",
33 "//external/crosvm",
34 "//external/libchromeos-rs",
35 "//external/vm_tools"
36 ]
37
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +010038class Env(object):
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +010039 def __init__(self, path):
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +010040 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 Stoep1b24dc32021-02-03 18:52:42 +010044 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 Stoep82ee11a2021-02-04 11:39:25 +010050 self.setup = True
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +010051 except:
Jeff Vander Stoep82ee11a2021-02-04 11:39:25 +010052 # Mark setup as failed if a path to a rust crate is not provided.
53 self.setup = False
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +010054
55class Bazel(object):
56 # set up the Bazel queryview
57 def __init__(self, env):
58 os.chdir(env.ANDROID_BUILD_TOP)
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +010059 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 Stoep82ee11a2021-02-04 11:39:25 +010063 self.setup = True
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +010064 except subprocess.CalledProcessError as e:
65 print("Error: Unable to update TEST_MAPPING due to the following build error:")
Jeff Vander Stoep82ee11a2021-02-04 11:39:25 +010066 print(e.output)
67 # Mark setup as failed if the Bazel queryview fails to build.
68 self.setup = False
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +010069 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 Stoepcec8bac2021-01-15 14:15:37 +010093 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 Stoepcec8bac2021-01-15 14:15:37 +010097 if '' in out:
98 out.remove('')
99 return out
100
Jeff Vander Stoep0b0e24f2021-01-24 20:50:26 +0100101 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 Stoepcec8bac2021-01-15 14:15:37 +0100107 # Return all reverse dependency tests for modules in this package.
108 def query_rdep_tests(self, modules):
109 rdep_tests = set()
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100110 for module in modules:
111 for rdep in self.query_rdeps(module):
Jeff Vander Stoep0b0e24f2021-01-24 20:50:26 +0100112 rule_type, tmp, mod = rdep.split(" ")
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100113 if rule_type == "rust_test_" or rule_type == "rust_test":
Jeff Vander Stoep0b0e24f2021-01-24 20:50:26 +0100114 if self.exclude_module(mod) == False:
115 rdep_tests.add(mod.split(":")[1].split("--")[0])
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100116 return rdep_tests
117
118
119class 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
128class TestMapping(object):
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +0100129 def __init__(self, path):
130 self.env = Env(path)
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100131 self.bazel = Bazel(self.env)
132
133 def create_test_mapping(self, path):
Jeff Vander Stoep82ee11a2021-02-04 11:39:25 +0100134 if self.env.setup == False or self.bazel.setup == False:
135 return
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100136 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 Stoep0b0e24f2021-01-24 20:50:26 +0100152 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 Stoepcec8bac2021-01-15 14:15:37 +0100158 return test_mapping
159
160 def write_test_mapping(self, test_mapping):
161 with open("TEST_MAPPING", "w") as json_file:
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +0100162 json_file.write("// Generated by update_crate_tests.py for tests that depend on this crate.\n")
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100163 json.dump(test_mapping, json_file, indent=2, separators=(',', ': '), sort_keys=True)
164 json_file.write("\n")
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +0100165 print("TEST_MAPPING successfully updated!")
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100166
167def main():
Jeff Vander Stoep1b24dc32021-02-03 18:52:42 +0100168 if len(sys.argv) == 2:
169 path = sys.argv[1]
170 else:
171 path = None
172 TestMapping(path).create_test_mapping(None)
Jeff Vander Stoepcec8bac2021-01-15 14:15:37 +0100173
174if __name__ == '__main__':
175 main()