1#! /usr/bin/env python3 2# 3# Copyright 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 17# Regenerate some ART test related files. 18 19# This script handles only a subset of ART run-tests at the moment; additional 20# cases will be added later. 21 22import argparse 23import copy 24import collections 25import itertools 26import json 27import logging 28import os 29import re 30import sys 31import textwrap 32import xml.dom.minidom 33 34logging.basicConfig(format='%(levelname)s: %(message)s') 35 36ME = os.path.basename(sys.argv[0]) 37 38# Common advisory placed at the top of all generated files. 39ADVISORY = f"Generated by `{ME}`. Do not edit manually." 40 41# Default indentation unit. 42INDENT = " " 43 44# Indentation unit for XML files. 45XML_INDENT = " " 46 47def reindent(str, indent = ""): 48 """Reindent literal string while removing common leading spaces.""" 49 return textwrap.indent(textwrap.dedent(str), indent) 50 51def copyright_header_text(year): 52 """Return the copyright header text used in XML files.""" 53 return reindent(f"""\ 54 Copyright (C) {year} The Android Open Source Project 55 56 Licensed under the Apache License, Version 2.0 (the "License"); 57 you may not use this file except in compliance with the License. 58 You may obtain a copy of the License at 59 60 http://www.apache.org/licenses/LICENSE-2.0 61 62 Unless required by applicable law or agreed to in writing, software 63 distributed under the License is distributed on an "AS IS" BASIS, 64 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 See the License for the specific language governing permissions and 66 limitations under the License. 67 """, " ") 68 69def split_list(l, n): 70 """Return a list of `n` sublists of (contiguous) elements of list `l`.""" 71 assert n > 0 72 (d, m) = divmod(len(l), n) 73 # If the length of `l` is divisible by `n`, use that that divisor (`d`) as size of each sublist; 74 # otherwise, the next integer value (`d + 1`). 75 s = d if m == 0 else d + 1 76 result = [l[i:i + s] for i in range(0, len(l), s)] 77 assert len(result) == n 78 return result 79 80# The prefix used in the Soong module name of all ART run-tests. 81ART_RUN_TEST_MODULE_NAME_PREFIX = "art-run-test-" 82 83# Number of shards used to declare ART run-tests in the sharded ART MTS test plan. 84NUM_MTS_ART_RUN_TEST_SHARDS = 1 85 86# Name of the ART MTS test list containing "eng-only" test modules, 87# which require a device-under-test running a `userdebug` or `eng` 88# build. 89ENG_ONLY_TEST_LIST_NAME = "mts-art-tests-list-eng-only" 90 91# Name of Lint baseline filename used in certain ART run-tests, 92# e.g. for the `NewApi` check (see e.g. b/268261262). 93LINT_BASELINE_FILENAME = "lint-baseline.xml" 94 95# Curated list of tests that have a custom `run` script, but that are 96# known to work fine with the default test execution strategy (i.e. 97# when ignoring their `run` script), even if not exactly as they would 98# with the original ART run-test harness. 99runnable_test_exceptions = frozenset([ 100 "059-finalizer-throw", 101 "080-oom-throw", 102 "133-static-invoke-super", 103 "159-app-image-fields", 104 "160-read-barrier-stress", 105 "163-app-image-methods", 106 "165-lock-owner-proxy", 107 "168-vmstack-annotated", 108 "176-app-image-string", 109 "304-method-tracing", 110 "628-vdex", 111 "643-checker-bogus-ic", 112 "676-proxy-jit-at-first-use", 113 "677-fsi2", 114 "678-quickening", 115 "818-clinit-nterp", 116 "821-madvise-willneed", 117 "1004-checker-volatile-ref-load", 118 "1338-gc-no-los", 119]) 120 121# Known slow tests, for which the timeout value is raised. 122known_slow_tests = frozenset([ 123 "080-oom-throw", 124 "099-vmdebug", 125 "109-suspend-check", 126 "175-alloc-big-bignums", 127]) 128 129# Known failing ART run-tests. 130# TODO(rpl): Investigate and address the causes of failures. 131known_failing_tests = frozenset([ 132 "004-SignalTest", 133 "004-UnsafeTest", 134 "051-thread", 135 # 055-enum-performance is time sensitive and disabled in test.py 136 "055-enum-performance", 137 "086-null-super", 138 "087-gc-after-link", 139 "136-daemon-jni-shutdown", 140 "139-register-natives", 141 "148-multithread-gc-annotations", 142 "149-suspend-all-stress", 143 "150-loadlibrary", 144 "154-gc-loop", 145 "169-threadgroup-jni", 146 "177-visibly-initialized-deadlock", 147 "179-nonvirtual-jni", 148 "203-multi-checkpoint", 149 "305-other-fault-handler", 150 # 449-checker-bce: Dependency on `libarttest`. 151 "449-checker-bce", 152 "454-get-vreg", 153 "461-get-reference-vreg", 154 "466-get-live-vreg", 155 "497-inlining-and-class-loader", 156 "530-regression-lse", 157 "555-UnsafeGetLong-regression", 158 # 596-monitor-inflation: Dependency on `libarttest`. 159 "596-monitor-inflation", 160 "602-deoptimizeable", 161 "604-hot-static-interface", 162 "616-cha-native", 163 "616-cha-regression-proxy-method", 164 # 623-checker-loop-regressions: Dependency on `libarttest`. 165 "623-checker-loop-regressions", 166 "626-set-resolved-string", 167 "642-fp-callees", 168 "647-jni-get-field-id", 169 "655-jit-clinit", 170 "656-loop-deopt", 171 "664-aget-verifier", 172 # 680-checker-deopt-dex-pc-0: Dependency on `libarttest`. 173 "680-checker-deopt-dex-pc-0", 174 "685-deoptimizeable", 175 "687-deopt", 176 "693-vdex-inmem-loader-evict", 177 "708-jit-cache-churn", 178 # 716-jli-jit-samples: Dependency on `libarttest`. 179 "716-jli-jit-samples", 180 "717-integer-value-of", 181 "720-thread-priority", 182 # 730-cha-deopt: Fails with: 183 # 184 # Test command execution failed with status FAILED: CommandResult: exit code=1, out=, err=Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 185 # at Main.main(Main.java:24) 186 # 187 "730-cha-deopt", 188 # 813-fp-args: Dependency on `libarttest`. 189 "813-fp-args", 190 # 821-many-args: Fails with: 191 # 192 # Test command execution failed with status FAILED: CommandResult: exit code=1, out=, err=Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 193 # at Main.main(Main.java:20) 194 # 195 "821-many-args", 196 # 823-cha-inlining: Dependency on `libarttest`. 197 "823-cha-inlining", 198 # 826-infinite-loop: The test expects an argument passed to `Main.main` (the test library, 199 # usually `arttestd` or `arttest)`, but the ART run-test TradeFed test runner 200 # (`com.android.tradefed.testtype.ArtRunTest`) does not implement this yet. 201 "826-infinite-loop", 202 # 832-cha-recursive: Dependency on `libarttest`. 203 "832-cha-recursive", 204 # 837-deopt: Dependency on `libarttest`. 205 "837-deopt", 206 # 844-exception: Dependency on `libarttest`. 207 "844-exception", 208 # 844-exception2: Dependency on `libarttest`. 209 "844-exception2", 210 # 966-default-conflict: Dependency on `libarttest`. 211 "966-default-conflict", 212 # These tests need native code. 213 "993-breakpoints-non-debuggable", 214 # 1002-notify-startup: Dependency on `libarttest` + custom `check` script. 215 "1002-notify-startup", 216 "1337-gc-coverage", 217 "1339-dead-reference-safe", 218 "1945-proxy-method-arguments", 219 "2011-stack-walk-concurrent-instrument", 220 "2033-shutdown-mechanics", 221 "2036-jni-filechannel", 222 "2037-thread-name-inherit", 223 # 2040-huge-native-alloc: Fails with: 224 # 225 # Test command execution failed with status FAILED: CommandResult: exit code=1, out=, err=Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 226 # at Main.main(Main.java:56) 227 # 228 "2040-huge-native-alloc", 229 "2235-JdkUnsafeTest", 230 "2243-single-step-default", 231 "2262-miranda-methods", 232 "2262-default-conflict-methods", 233 # 2275-pthread-name: Dependency on `libarttest`. 234 "2275-pthread-name", 235]) 236 237# These ART run-tests are new and have not had enough post-submit runs 238# to meet pre-submit SLOs. Monitor their post-submit runs before 239# removing them from this set (in order to promote them to 240# presubmits). 241postsubmit_only_tests = frozenset([ 242]) 243 244known_failing_on_hwasan_tests = frozenset([ 245 "CtsJdwpTestCases", # times out 246 # apexd fails to unmount com.android.runtime on ASan builds. 247 "art_standalone_dexopt_chroot_setup_tests", 248]) 249 250# ART gtests that do not need root access to the device. 251art_gtest_user_module_names = [ 252 "art_libnativebridge_cts_tests", 253 "art_standalone_artd_tests", 254 "art_standalone_cmdline_tests", 255 "art_standalone_compiler_tests", 256 "art_standalone_dex2oat_cts_tests", 257 "art_standalone_dex2oat_tests", 258 "art_standalone_dexdump_tests", 259 "art_standalone_dexlist_tests", 260 "art_standalone_libartbase_tests", 261 "art_standalone_libartpalette_tests", 262 "art_standalone_libartservice_tests", 263 "art_standalone_libarttools_tests", 264 "art_standalone_libdexfile_support_tests", 265 "art_standalone_libdexfile_tests", 266 "art_standalone_libprofile_tests", 267 "art_standalone_oatdump_tests", 268 "art_standalone_odrefresh_tests", 269 "art_standalone_runtime_tests", 270 "art_standalone_sigchain_tests", 271 "libnativebridge-lazy-tests", 272 "libnativebridge-tests", 273 "libnativeloader_test", 274] 275 276# ART gtests that need root access to the device. 277art_gtest_eng_only_module_names = [ 278 "art_standalone_dexopt_chroot_setup_tests", 279 "art_standalone_dexoptanalyzer_tests", 280 "art_standalone_profman_tests", 281 "libnativeloader_e2e_tests", 282] 283 284# All supported ART gtests. 285art_gtest_module_names = sorted(art_gtest_user_module_names + art_gtest_eng_only_module_names) 286 287# These ART gtests are new and have not had enough post-submit runs 288# to meet pre-submit SLOs. Monitor their post-submit runs before 289# removing them from this set (in order to promote them to 290# presubmits). 291art_gtest_postsubmit_only_module_names = [ 292] 293 294# ART gtests not supported in MTS. 295art_gtest_modules_excluded_from_mts = [ 296 # TODO(b/347717488): Consider adding this test to ART MTS. 297 "libnativebridge-tests", 298] 299 300# ART gtests supported in MTS that do not need root access to the device. 301art_gtest_mts_user_module_names = [t for t in art_gtest_user_module_names 302 if t not in art_gtest_modules_excluded_from_mts] 303 304# ART gtests supported in presubmits. 305art_gtest_presubmit_module_names = [t for t in art_gtest_module_names 306 if t not in art_gtest_postsubmit_only_module_names] 307 308# ART gtests supported in Mainline presubmits. 309art_gtest_mainline_presubmit_module_names = copy.copy(art_gtest_presubmit_module_names) 310 311# ART gtests supported in postsubmits. 312unknown_art_gtest_postsubmit_only_module_names = [t for t in art_gtest_postsubmit_only_module_names 313 if t not in art_gtest_module_names] 314if unknown_art_gtest_postsubmit_only_module_names: 315 logging.error(textwrap.dedent("""\ 316 The following `art_gtest_postsubmit_only_module_names` elements are not part of 317 `art_gtest_module_names`: """) + str(unknown_art_gtest_postsubmit_only_module_names)) 318 sys.exit(1) 319art_gtest_postsubmit_module_names = copy.copy(art_gtest_postsubmit_only_module_names) 320 321# Tests exhibiting a flaky behavior, currently exluded from MTS for 322# the stake of stability / confidence (b/209958457). 323flaky_tests_excluded_from_mts = { 324 "CtsLibcoreFileIOTestCases": [ 325 ("android.cts.FileChannelInterProcessLockTest#" + m) for m in [ 326 "test_lockJJZ_Exclusive_asyncChannel", 327 "test_lockJJZ_Exclusive_syncChannel", 328 "test_lock_differentChannelTypes", 329 "test_lockJJZ_Shared_asyncChannel", 330 "test_lockJJZ_Shared_syncChannel", 331 ] 332 ], 333 "CtsLibcoreTestCases": [ 334 ("com.android.org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest#" + m + c) 335 for (m, c) in itertools.product( 336 [ 337 "test_SSLSocket_interrupt_read_withoutAutoClose", 338 "test_SSLSocket_setSoWriteTimeout", 339 ], 340 [ 341 "[0: TLSv1.2 client, TLSv1.2 server]", 342 "[1: TLSv1.2 client, TLSv1.3 server]", 343 "[2: TLSv1.3 client, TLSv1.2 server]", 344 "[3: TLSv1.3 client, TLSv1.3 server]", 345 ] 346 ) 347 ] + [ 348 ("libcore.dalvik.system.DelegateLastClassLoaderTest#" + m) for m in [ 349 "testLookupOrderNodelegate_getResource", 350 "testLookupOrder_getResource", 351 ] 352 ] 353} 354 355# Tests excluded from all test mapping test groups. 356# 357# Example of admissible values in this dictionary: 358# 359# "art_standalone_cmdline_tests": ["CmdlineParserTest#TestCompilerOption"], 360# "art_standalone_dexopt_chroot_setup_tests": ["DexoptChrootSetupTest#HelloWorld"], 361# 362failing_tests_excluded_from_test_mapping = { 363 # Empty. 364} 365 366# Tests failing because of linking issues, currently exluded from MTS 367# and Mainline Presubmits to minimize noise in continuous runs while 368# we investigate. 369# 370# Example of admissible values in this dictionary: same as for 371# `failing_tests_excluded_from_test_mapping` (see above). 372# 373# TODO(b/247108425): Address the linking issues and re-enable these 374# tests. 375failing_tests_excluded_from_mts_and_mainline_presubmits = { 376 "art_standalone_compiler_tests": ["JniCompilerTest*"], 377 "art_standalone_libartpalette_tests": ["PaletteClientJniTest*"], 378} 379 380failing_tests_excluded_from_mainline_presubmits = ( 381 failing_tests_excluded_from_test_mapping | 382 failing_tests_excluded_from_mts_and_mainline_presubmits 383) 384 385# Is `run_test` a Checker test (i.e. a test containing Checker 386# assertions)? 387def is_checker_test(run_test): 388 return re.match("^[0-9]+-checker-", run_test) 389 390def gen_mts_test_list_file(tests, test_list_file, copyright_year, configuration_description, 391 tests_description, comments = []): 392 """Generate an ART MTS test list file.""" 393 root = xml.dom.minidom.Document() 394 395 advisory_header = root.createComment(f" {ADVISORY} ") 396 root.appendChild(advisory_header) 397 copyright_header = root.createComment(copyright_header_text(copyright_year)) 398 root.appendChild(copyright_header) 399 400 configuration = root.createElement("configuration") 401 root.appendChild(configuration) 402 configuration.setAttribute("description", configuration_description) 403 404 def append_option(name, value): 405 option = root.createElement("option") 406 option.setAttribute("name", name) 407 option.setAttribute("value", value) 408 configuration.appendChild(option) 409 410 def append_comment(comment): 411 xml_comment = root.createComment(f" {comment} ") 412 configuration.appendChild(xml_comment) 413 414 # Test declarations. 415 # ------------------ 416 417 test_declarations_comments = [tests_description + "."] 418 test_declarations_comments.extend(comments) 419 for c in test_declarations_comments: 420 append_comment(c) 421 for t in tests: 422 append_option("compatibility:include-filter", t) 423 424 # `MainlineTestModuleController` configurations. 425 # ---------------------------------------------- 426 427 module_controller_configuration_comments = [ 428 f"Enable MainlineTestModuleController for {tests_description}."] 429 module_controller_configuration_comments.extend(comments) 430 for c in module_controller_configuration_comments: 431 append_comment(c) 432 for t in tests: 433 append_option("compatibility:module-arg", f"{t}:enable:true") 434 for t in tests: 435 if t in ["CtsLibcoreTestCases", "CtsLibcoreOjTestCases"]: 436 append_comment("core-test-mode=mts tells ExpectationBasedFilter to exclude @NonMts Tests") 437 append_option("compatibility:module-arg", f"{t}:instrumentation-arg:core-test-mode:=mts") 438 439 xml_str = root.toprettyxml(indent = XML_INDENT, encoding = "utf-8") 440 441 with open(test_list_file, "wb") as f: 442 logging.debug(f"Writing `{test_list_file}`.") 443 f.write(xml_str) 444 445class Generator: 446 def __init__(self, top_dir): 447 """Generator of ART test files for an Android source tree anchored at `top_dir`.""" 448 # Path to the Android top source tree. 449 self.top_dir = top_dir 450 # Path to the ART directory 451 self.art_dir = os.path.join(top_dir, "art") 452 # Path to the ART tests top-level directory. 453 self.art_test_dir = os.path.join(self.art_dir, "test") 454 # Path to the MTS configuration directory. 455 self.mts_config_dir = os.path.join( 456 top_dir, "test", "mts", "tools", "mts-tradefed", "res", "config") 457 # Path to the ART JVM TI CTS tests top-level directory. 458 self.jvmti_cts_test_dir = os.path.join(top_dir, "cts/hostsidetests/jvmti/run-tests") 459 460 # Return the list of ART run-tests (in short form, i.e. `001-HelloWorld`, 461 # not `art-run-test-001-HelloWorld`). 462 def enumerate_run_tests(self): 463 return sorted([run_test 464 for run_test in os.listdir(self.art_test_dir) 465 if re.match("^[0-9]{3,}-", run_test)]) 466 467 # Return the list of ART JVM TI CTS tests. 468 def enumerate_jvmti_cts_tests(self): 469 return sorted([re.sub(r"test-(\d+)", r"CtsJvmtiRunTest\1HostTestCases", cts_jvmti_test_dir) 470 for cts_jvmti_test_dir in os.listdir(self.jvmti_cts_test_dir) 471 if re.match(r"^test-\d+$", cts_jvmti_test_dir)]) 472 473 # Return the metadata of a test, if any. 474 def get_test_metadata(self, run_test): 475 run_test_path = os.path.join(self.art_test_dir, run_test) 476 metadata_file = os.path.join(run_test_path, "test-metadata.json") 477 metadata = {} 478 if os.path.exists(metadata_file): 479 with open(metadata_file, "r") as f: 480 try: 481 metadata = json.load(f) 482 except json.decoder.JSONDecodeError: 483 logging.error(f"Unable to parse test metadata file `{metadata_file}`") 484 raise 485 return metadata 486 487 # Can the build script of `run_test` be safely ignored? 488 def can_ignore_build_script(self, run_test): 489 # Check whether there are test metadata with build parameters 490 # enabling us to safely ignore the build script. 491 metadata = self.get_test_metadata(run_test) 492 build_param = metadata.get("build-param", {}) 493 # Ignore build scripts that are just about preventing building for 494 # the JVM and/or using VarHandles (Soong builds JARs with 495 # VarHandle support by default (i.e. by using an API level greater 496 # or equal to 28), so we can ignore build scripts that just 497 # request support for this feature.) 498 experimental_var_handles = {"experimental": "var-handles"} 499 jvm_supported_false = {"jvm-supported": "false"} 500 if (build_param == experimental_var_handles or 501 build_param == jvm_supported_false or 502 build_param == experimental_var_handles | jvm_supported_false): 503 return True 504 return False 505 506 # Can `run_test` be built with Soong? 507 # TODO(b/147814778): Add build support for more tests. 508 def is_soong_buildable(self, run_test): 509 run_test_path = os.path.join(self.art_test_dir, run_test) 510 511 # Skip tests with non-default build rules, unless these build 512 # rules can be safely ignored. 513 if (os.path.isfile(os.path.join(run_test_path, "generate-sources")) or 514 os.path.isfile(os.path.join(run_test_path, "javac_post.sh"))): 515 return False 516 if os.path.isfile(os.path.join(run_test_path, "build.py")): 517 if not self.can_ignore_build_script(run_test): 518 return False 519 # Skip tests with sources outside the `src` directory. 520 for subdir in ["jasmin", 521 "jasmin-multidex", 522 "smali", 523 "smali-ex", 524 "smali-multidex", 525 "src-aotex", 526 "src-bcpex", 527 "src-ex", 528 "src-ex2", 529 "src-multidex"]: 530 if os.path.isdir(os.path.join(run_test_path, subdir)): 531 return False 532 # Skip tests that have both an `src` directory and an `src-art` directory. 533 if os.path.isdir(os.path.join(run_test_path, "src")) and \ 534 os.path.isdir(os.path.join(run_test_path, "src-art")): 535 return False 536 # Skip tests that have neither an `src` directory nor an `src-art` directory. 537 if not os.path.isdir(os.path.join(run_test_path, "src")) and \ 538 not os.path.isdir(os.path.join(run_test_path, "src-art")): 539 return False 540 # Skip test with a copy of `sun.misc.Unsafe`. 541 if os.path.isfile(os.path.join(run_test_path, "src", "sun", "misc", "Unsafe.java")): 542 return False 543 # Skip tests with Hidden API specs. 544 if os.path.isfile(os.path.join(run_test_path, "hiddenapi-flags.csv")): 545 return False 546 # All other tests are considered buildable. 547 return True 548 549 # Can the run script of `run_test` be safely ignored? 550 def can_ignore_run_script(self, run_test): 551 # Unconditionally consider some identified tests that have a 552 # (not-yet-handled) custom `run` script as runnable. 553 # 554 # TODO(rpl): Get rid of this exception mechanism by supporting 555 # these tests' `run` scripts properly. 556 if run_test in runnable_test_exceptions: 557 return True 558 # Check whether there are test metadata with run parameters 559 # enabling us to safely ignore the run script. 560 metadata = self.get_test_metadata(run_test) 561 run_param = metadata.get("run-param", {}) 562 if run_param.get("default-run", ""): 563 return True 564 return False 565 566 # Generate a Blueprint property group as a string, i.e. something looking like 567 # this: 568 # 569 # ``` 570 # <group_name>: { 571 # <key0>: "<value0>", 572 # ... 573 # <keyN>: "<valueN>", 574 # } 575 # ``` 576 # 577 # where `(key0, value0), ..., (keyN, valueN)` are key-value pairs in `props`. 578 def gen_prop_group(self, group_name, props): 579 props_joined = """, 580 """.join([f"{k}: \"{v}\"" for (k, v) in props.items()]) 581 return f""" 582 {group_name}: {{ 583 {props_joined}, 584 }},""" 585 586 def gen_libs_list_impl(self, library_type, libraries): 587 if len(libraries) == 0: 588 return "" 589 libraries_joined = """, 590 """.join(libraries) 591 return f""" 592 {library_type}: [ 593 {libraries_joined}, 594 ],""" 595 596 def gen_libs_list(self, libraries): 597 return self.gen_libs_list_impl("libs", libraries); 598 599 def gen_static_libs_list(self, libraries): 600 return self.gen_libs_list_impl("static_libs", libraries); 601 602 def gen_java_library_rule(self, name, src_dir, libraries, extra_props): 603 return f"""\ 604 605 606 // Library with {src_dir}/ sources for the test. 607 java_library {{ 608 name: "{name}", 609 defaults: ["art-run-test-defaults"],{self.gen_libs_list(libraries)} 610 srcs: ["{src_dir}/**/*.java"],{extra_props} 611 }}""" 612 613 # Can `run_test` be succesfully run with TradeFed? 614 # TODO(b/147812905): Add run-time support for more tests. 615 def is_tradefed_runnable(self, run_test): 616 run_test_path = os.path.join(self.art_test_dir, run_test) 617 618 # Skip tests with non-default run rules, unless these run rules 619 # can be safely ignored. 620 if os.path.isfile(os.path.join(run_test_path, "run.py")): 621 if not self.can_ignore_run_script(run_test): 622 return False 623 # Skip tests known to fail. 624 if run_test in known_failing_tests: 625 return False 626 # All other tests are considered runnable. 627 return True 628 629 def is_slow(self, run_test): 630 return run_test in known_slow_tests 631 632 def regen_bp_files(self, run_tests, buildable_tests): 633 for run_test in run_tests: 634 # Remove any previously generated file. 635 bp_file = os.path.join(self.art_test_dir, run_test, "Android.bp") 636 if os.path.exists(bp_file): 637 logging.debug(f"Removing `{bp_file}`.") 638 os.remove(bp_file) 639 640 for run_test in buildable_tests: 641 self.regen_bp_file(run_test) 642 643 def regen_bp_file(self, run_test): 644 """Regenerate Blueprint file for an ART run-test.""" 645 646 run_test_path = os.path.join(self.art_test_dir, run_test) 647 bp_file = os.path.join(run_test_path, "Android.bp") 648 649 # Optional test metadata (JSON file). 650 metadata = self.get_test_metadata(run_test) 651 test_suites = metadata.get("test_suites", []) 652 is_cts_test = "cts" in test_suites 653 is_mcts_test = "mcts-art" in test_suites 654 655 # For now we make it mandatory for an ART CTS test to be an ART 656 # MCTS test and vice versa. 657 if is_cts_test != is_mcts_test: 658 (present, absent) = ("mts", "mcts-art") if is_cts_test else ("mcts-art", "mts") 659 logging.error(f"Inconsistent test suites state in metadata for ART run-test `{run_test}`: " + 660 f"`test_suites` contains `{present}` but not `{absent}`") 661 sys.exit(1) 662 663 # Do not package non-runnable ART run-tests in ART MTS (see b/363075236). 664 if self.is_tradefed_runnable(run_test): 665 test_suites.append("mts-art") 666 667 run_test_module_name = ART_RUN_TEST_MODULE_NAME_PREFIX + run_test 668 669 # Set the test configuration template. 670 if self.is_tradefed_runnable(run_test): 671 if is_cts_test: 672 test_config_template = "art-run-test-target-cts-template" 673 elif self.is_slow(run_test): 674 test_config_template = "art-run-test-target-slow-template" 675 else: 676 test_config_template = "art-run-test-target-template" 677 else: 678 test_config_template = "art-run-test-target-no-test-suite-tag-template" 679 680 # Define the `test_suites` property, if test suites are present in 681 # the test's metadata. 682 test_suites_prop = "" 683 if test_suites: 684 test_suites_joined = """, 685 """.join([f"\"{s}\"" for s in test_suites]) 686 test_suites_prop = f"""\ 687 688 test_suites: [ 689 {test_suites_joined}, 690 ],""" 691 692 include_srcs_prop = "" 693 if is_checker_test(run_test): 694 include_srcs_prop = """\ 695 696 // Include the Java source files in the test's artifacts, to make Checker assertions 697 // available to the TradeFed test runner. 698 include_srcs: true,""" 699 700 # Set the version of the SDK to compile the Java test module 701 # against, if needed. 702 sdk_version_prop = "" 703 if is_cts_test: 704 # Have CTS and MCTS test modules use the test API 705 # (`test_current`) so that they do not depend on the framework 706 # private platform API (`private`), which is the default. 707 sdk_version_prop = """ 708 sdk_version: "test_current",""" 709 710 # The default source directory is `src`, except if `src-art` exists. 711 if os.path.isdir(os.path.join(run_test_path, "src-art")): 712 source_dir = "src-art" 713 else: 714 source_dir = "src" 715 716 src_library_rules = [] 717 test_libraries = [] 718 extra_props = "" 719 # Honor the Lint baseline file, if present. 720 if os.path.isfile(os.path.join(run_test_path, LINT_BASELINE_FILENAME)): 721 extra_props += self.gen_prop_group("lint", {"baseline_filename": LINT_BASELINE_FILENAME}) 722 if os.path.isdir(os.path.join(run_test_path, "src2")): 723 test_library = f"{run_test_module_name}-{source_dir}" 724 src_library_rules.append( 725 self.gen_java_library_rule(test_library, source_dir, test_libraries, extra_props)) 726 test_libraries.append(f"\"{test_library}\"") 727 source_dir = "src2" 728 729 with open(bp_file, "w") as f: 730 logging.debug(f"Writing `{bp_file}`.") 731 f.write(textwrap.dedent(f"""\ 732 // {ADVISORY} 733 734 // Build rules for ART run-test `{run_test}`. 735 736 package {{ 737 // See: http://go/android-license-faq 738 // A large-scale-change added 'default_applicable_licenses' to import 739 // all of the 'license_kinds' from "art_license" 740 // to get the below license kinds: 741 // SPDX-license-identifier-Apache-2.0 742 default_applicable_licenses: ["art_license"], 743 }}{''.join(src_library_rules)} 744 745 // Test's Dex code. 746 java_test {{ 747 name: "{run_test_module_name}", 748 defaults: ["art-run-test-defaults"], 749 test_config_template: ":{test_config_template}", 750 srcs: ["{source_dir}/**/*.java"],{self.gen_static_libs_list(test_libraries)} 751 data: [ 752 ":{run_test_module_name}-expected-stdout", 753 ":{run_test_module_name}-expected-stderr", 754 ],{test_suites_prop}{include_srcs_prop}{sdk_version_prop} 755 }} 756 """)) 757 758 def add_expected_output_genrule(type_str): 759 type_str_long = "standard output" if type_str == "stdout" else "standard error" 760 in_file = os.path.join(run_test_path, f"expected-{type_str}.txt") 761 if os.path.islink(in_file): 762 # Genrules are sandboxed, so if we just added the symlink to the srcs list, it would 763 # be a dangling symlink in the sandbox. Instead, if we see a symlink, depend on the 764 # genrule from the test that the symlink is pointing to instead of the symlink itself. 765 link_target = os.readlink(in_file) 766 basename = os.path.basename(in_file) 767 match = re.fullmatch('\.\./([a-zA-Z0-9_-]+)/' + re.escape(basename), link_target) 768 if not match: 769 sys.exit(f"Error: expected symlink to be '../something/{basename}', got {link_target}") 770 f.write(textwrap.dedent(f"""\ 771 772 // Test's expected {type_str_long}. 773 genrule {{ 774 name: "{run_test_module_name}-expected-{type_str}", 775 out: ["{run_test_module_name}-expected-{type_str}.txt"], 776 srcs: [":{ART_RUN_TEST_MODULE_NAME_PREFIX}{match.group(1)}-expected-{type_str}"], 777 cmd: "cp -f $(in) $(out)", 778 }} 779 """)) 780 else: 781 f.write(textwrap.dedent(f"""\ 782 783 // Test's expected {type_str_long}. 784 genrule {{ 785 name: "{run_test_module_name}-expected-{type_str}", 786 out: ["{run_test_module_name}-expected-{type_str}.txt"], 787 srcs: ["expected-{type_str}.txt"], 788 cmd: "cp -f $(in) $(out)", 789 }} 790 """)) 791 792 add_expected_output_genrule("stdout") 793 add_expected_output_genrule("stderr") 794 795 796 def regen_test_mapping_file(self, art_run_tests): 797 """Regenerate ART's `TEST_MAPPING`.""" 798 799 # See go/test-mapping#attributes and 800 # https://source.android.com/docs/core/tests/development/test-mapping 801 # for more information about Test Mapping test groups. 802 803 # ART run-tests used in `*presubmit` test groups, used both in pre- and post-submit runs. 804 presubmit_run_test_module_names = [ART_RUN_TEST_MODULE_NAME_PREFIX + t 805 for t in art_run_tests 806 if t not in postsubmit_only_tests] 807 # ART run-tests used in the `postsubmit` test group, used in post-submit runs only. 808 postsubmit_run_test_module_names = [ART_RUN_TEST_MODULE_NAME_PREFIX + t 809 for t in art_run_tests 810 if t in postsubmit_only_tests] 811 812 def gen_tests_dict(tests, excluded_test_cases = {}, excluded_test_modules = [], suffix = ""): 813 return [ 814 ({"name": t + suffix, 815 "options": [ 816 {"exclude-filter": e} 817 for e in excluded_test_cases[t] 818 ]} 819 if t in excluded_test_cases 820 else {"name": t + suffix}) 821 for t in tests 822 if t not in excluded_test_modules 823 ] 824 825 # Mainline presubmits. 826 mainline_presubmit_apex_suffix = "[com.google.android.art.apex]" 827 mainline_other_presubmit_tests = [] 828 mainline_presubmit_tests = (mainline_other_presubmit_tests + presubmit_run_test_module_names + 829 art_gtest_mainline_presubmit_module_names) 830 mainline_presubmit_tests_dict = \ 831 gen_tests_dict(mainline_presubmit_tests, 832 failing_tests_excluded_from_mainline_presubmits, 833 [], 834 mainline_presubmit_apex_suffix) 835 836 # ART mainline presubmits tests without APEX suffix 837 art_mainline_presubmit_tests_dict = \ 838 gen_tests_dict(mainline_presubmit_tests, 839 failing_tests_excluded_from_mainline_presubmits, 840 [], 841 "") 842 843 # Android Virtualization Framework presubmits 844 avf_presubmit_tests = ["ComposHostTestCases"] 845 avf_presubmit_tests_dict = gen_tests_dict(avf_presubmit_tests, 846 failing_tests_excluded_from_test_mapping) 847 848 # Presubmits. 849 other_presubmit_tests = [ 850 "ArtServiceTests", 851 "BootImageProfileTest", 852 "CtsJdwpTestCases", 853 "art-apex-update-rollback", 854 "art_standalone_dexpreopt_tests", 855 ] 856 presubmit_tests = (other_presubmit_tests + presubmit_run_test_module_names + 857 art_gtest_presubmit_module_names) 858 presubmit_tests_dict = gen_tests_dict(presubmit_tests, 859 failing_tests_excluded_from_test_mapping) 860 hwasan_presubmit_tests_dict = gen_tests_dict(presubmit_tests, 861 failing_tests_excluded_from_test_mapping, 862 known_failing_on_hwasan_tests) 863 864 # Postsubmits. 865 postsubmit_tests = postsubmit_run_test_module_names + art_gtest_postsubmit_module_names 866 postsubmit_tests_dict = [{"name": t} for t in postsubmit_tests] 867 postsubmit_tests_dict = gen_tests_dict(postsubmit_tests, 868 failing_tests_excluded_from_test_mapping) 869 870 # Use an `OrderedDict` container to preserve the order in which items are inserted. 871 # Do not produce an entry for a test group if it is empty. 872 test_mapping_dict = collections.OrderedDict([ 873 (test_group_name, test_group_dict) 874 for (test_group_name, test_group_dict) 875 in [ 876 ("art-mainline-presubmit", art_mainline_presubmit_tests_dict), 877 ("mainline-presubmit", mainline_presubmit_tests_dict), 878 ("presubmit", presubmit_tests_dict), 879 ("hwasan-presubmit", hwasan_presubmit_tests_dict), 880 ("avf-presubmit", avf_presubmit_tests_dict), 881 ("postsubmit", postsubmit_tests_dict), 882 ] 883 if test_group_dict 884 ]) 885 test_mapping_contents = json.dumps(test_mapping_dict, indent = INDENT) 886 887 test_mapping_file = os.path.join(self.art_dir, "TEST_MAPPING") 888 with open(test_mapping_file, "w") as f: 889 logging.debug(f"Writing `{test_mapping_file}`.") 890 f.write(f"// {ADVISORY}\n") 891 f.write(test_mapping_contents) 892 f.write("\n") 893 894 def create_mts_test_shard(self, tests_description, tests, shard_num, copyright_year, 895 comments = []): 896 """Factory method instantiating an `MtsTestShard`.""" 897 return self.MtsTestShard(self.mts_config_dir, tests_description, tests, shard_num, 898 copyright_year, comments) 899 900 class MtsTestShard: 901 """Class encapsulating data and generation logic for an ART MTS test shard.""" 902 903 def __init__(self, mts_config_dir, tests_description, tests, shard_num, copyright_year, 904 comments): 905 self.mts_config_dir = mts_config_dir 906 self.tests_description = tests_description 907 self.tests = tests 908 self.shard_num = shard_num 909 self.copyright_year = copyright_year 910 self.comments = comments 911 912 def shard_id(self): 913 return f"{self.shard_num:02}" 914 915 def test_plan_name(self): 916 return "mts-art-shard-" + self.shard_id() 917 918 def test_list_name(self): 919 return "mts-art-tests-list-user-shard-" + self.shard_id() 920 921 def regen_test_plan_file(self): 922 """Regenerate ART MTS test plan file shard (`mts-art-shard-<shard_num>.xml`).""" 923 root = xml.dom.minidom.Document() 924 925 advisory_header = root.createComment(f" {ADVISORY} ") 926 root.appendChild(advisory_header) 927 copyright_header = root.createComment(copyright_header_text(self.copyright_year)) 928 root.appendChild(copyright_header) 929 930 configuration = root.createElement("configuration") 931 root.appendChild(configuration) 932 configuration.setAttribute( 933 "description", 934 f"Run {self.test_plan_name()} from a preexisting MTS installation.") 935 936 # Included XML files. 937 included_xml_files = ["mts", self.test_list_name()] 938 # Special case for the test plan of shard 03 (ART gtests), where we also 939 # include ART MTS eng-only tests. 940 # 941 # TODO(rpl): Restucture the MTS generation logic to avoid special-casing 942 # at that level of the generator. 943 if self.shard_num == 3: 944 included_xml_files.append(ENG_ONLY_TEST_LIST_NAME) 945 for xml_file in included_xml_files: 946 include = root.createElement("include") 947 include.setAttribute("name", xml_file) 948 configuration.appendChild(include) 949 950 # Test plan name. 951 option = root.createElement("option") 952 option.setAttribute("name", "plan") 953 option.setAttribute("value", self.test_plan_name()) 954 configuration.appendChild(option) 955 956 xml_str = root.toprettyxml(indent = XML_INDENT, encoding = "utf-8") 957 958 test_plan_file = os.path.join(self.mts_config_dir, self.test_plan_name() + ".xml") 959 with open(test_plan_file, "wb") as f: 960 logging.debug(f"Writing `{test_plan_file}`.") 961 f.write(xml_str) 962 963 def regen_test_list_file(self): 964 """Regenerate ART MTS test list file (`mts-art-tests-list-user-shard-<shard_num>.xml`).""" 965 configuration_description = \ 966 f"List of ART MTS tests that do not need root access (shard {self.shard_id()})" 967 test_list_file = os.path.join(self.mts_config_dir, self.test_list_name() + ".xml") 968 gen_mts_test_list_file(self.tests, test_list_file, self.copyright_year, 969 configuration_description, self.tests_description, self.comments) 970 971 def regen_mts_art_tests_list_user_file(self, num_mts_art_run_test_shards): 972 """Regenerate ART MTS test list file (`mts-art-tests-list-user.xml`).""" 973 root = xml.dom.minidom.Document() 974 975 advisory_header = root.createComment(f" {ADVISORY} ") 976 root.appendChild(advisory_header) 977 copyright_header = root.createComment(copyright_header_text(2020)) 978 root.appendChild(copyright_header) 979 980 configuration = root.createElement("configuration") 981 root.appendChild(configuration) 982 configuration.setAttribute("description", "List of ART MTS tests that do not need root access.") 983 984 # Included XML files. 985 for s in range(num_mts_art_run_test_shards): 986 include = root.createElement("include") 987 include.setAttribute("name", f"mts-art-tests-list-user-shard-{s:02}") 988 configuration.appendChild(include) 989 990 def append_test_exclusion(test): 991 option = root.createElement("option") 992 option.setAttribute("name", "compatibility:exclude-filter") 993 option.setAttribute("value", test) 994 configuration.appendChild(option) 995 996 # Excluded flaky tests. 997 xml_comment = root.createComment(" Excluded flaky tests (b/209958457). ") 998 configuration.appendChild(xml_comment) 999 for module in flaky_tests_excluded_from_mts: 1000 for testcase in flaky_tests_excluded_from_mts[module]: 1001 append_test_exclusion(f"{module} {testcase}") 1002 1003 # Excluded failing tests. 1004 xml_comment = root.createComment(" Excluded failing tests (b/247108425). ") 1005 configuration.appendChild(xml_comment) 1006 for module in failing_tests_excluded_from_mts_and_mainline_presubmits: 1007 for testcase in failing_tests_excluded_from_mts_and_mainline_presubmits[module]: 1008 append_test_exclusion(f"{module} {testcase}") 1009 1010 xml_str = root.toprettyxml(indent = XML_INDENT, encoding = "utf-8") 1011 1012 mts_art_tests_list_user_file = os.path.join(self.mts_config_dir, "mts-art-tests-list-user.xml") 1013 with open(mts_art_tests_list_user_file, "wb") as f: 1014 logging.debug(f"Writing `{mts_art_tests_list_user_file}`.") 1015 f.write(xml_str) 1016 1017 def regen_art_mts_files(self, art_run_tests, art_jvmti_cts_tests): 1018 """Regenerate ART MTS definition files.""" 1019 1020 # Remove any previously MTS ART test plan shard (`mts-art-shard-[0-9]+.xml`) 1021 # and any test list shard (`mts-art-tests-list-user-shard-[0-9]+.xml`). 1022 old_test_plan_shards = sorted([ 1023 test_plan_shard 1024 for test_plan_shard in os.listdir(self.mts_config_dir) 1025 if re.match("^mts-art-(tests-list-user-)?shard-[0-9]+.xml$", test_plan_shard)]) 1026 for shard in old_test_plan_shards: 1027 shard_path = os.path.join(self.mts_config_dir, shard) 1028 if os.path.exists(shard_path): 1029 logging.debug(f"Removing `{shard_path}`.") 1030 os.remove(shard_path) 1031 1032 mts_test_shards = [] 1033 1034 # ART run-tests shard(s). 1035 art_run_test_module_names = [ART_RUN_TEST_MODULE_NAME_PREFIX + t for t in art_run_tests] 1036 art_run_test_shards = split_list(art_run_test_module_names, NUM_MTS_ART_RUN_TEST_SHARDS) 1037 for i in range(len(art_run_test_shards)): 1038 art_tests_shard_i_tests = art_run_test_shards[i] 1039 art_tests_shard_i = self.create_mts_test_shard( 1040 "ART run-tests", art_tests_shard_i_tests, i, 2020, 1041 ["TODO(rpl): Find a way to express this list in a more concise fashion."]) 1042 mts_test_shards.append(art_tests_shard_i) 1043 1044 # CTS Libcore non-OJ tests (`CtsLibcoreTestCases`) shard. 1045 cts_libcore_tests_shard_num = len(mts_test_shards) 1046 cts_libcore_tests_shard = self.create_mts_test_shard( 1047 "CTS Libcore non-OJ tests", ["CtsLibcoreTestCases"], cts_libcore_tests_shard_num, 2020) 1048 mts_test_shards.append(cts_libcore_tests_shard) 1049 1050 # Other CTS tests shard. 1051 other_cts_tests_shard_num = len(mts_test_shards) 1052 other_cts_libcore_tests_shard_tests = [ 1053 "CtsLibcoreApiEvolutionTestCases", 1054 "CtsLibcoreFileIOTestCases", 1055 "CtsLibcoreJsr166TestCases", 1056 "CtsLibcoreLegacy22TestCases", 1057 "CtsLibcoreOjTestCases", 1058 "CtsLibcoreWycheproofBCTestCases", 1059 "MtsLibcoreOkHttpTestCases", 1060 "MtsLibcoreBouncyCastleTestCases", 1061 ] 1062 other_cts_tests_shard_tests = art_jvmti_cts_tests + other_cts_libcore_tests_shard_tests 1063 other_cts_tests_shard = self.create_mts_test_shard( 1064 "Other CTS tests", other_cts_tests_shard_tests, other_cts_tests_shard_num, 2021) 1065 mts_test_shards.append(other_cts_tests_shard) 1066 1067 # ART gtests shard. 1068 art_gtests_shard_num = len(mts_test_shards) 1069 art_gtests_shard_tests = art_gtest_mts_user_module_names 1070 art_gtests_shard = self.create_mts_test_shard( 1071 "ART gtests", art_gtests_shard_tests, art_gtests_shard_num, 2022) 1072 mts_test_shards.append(art_gtests_shard) 1073 1074 for s in mts_test_shards: 1075 s.regen_test_plan_file() 1076 s.regen_test_list_file() 1077 1078 # Generate the MTS test list file of "eng-only" tests (tests that 1079 # need root access to the device-under-test and are not part of 1080 # "user" test plans). 1081 # 1082 # TODO(rpl): Refactor the MTS file generation logic to better 1083 # handle the special case of "eng-only" tests, which do not play 1084 # well with `MtsTestShard` at the moment). 1085 eng_only_test_list_file = os.path.join(self.mts_config_dir, ENG_ONLY_TEST_LIST_NAME + ".xml") 1086 gen_mts_test_list_file( 1087 art_gtest_eng_only_module_names, eng_only_test_list_file, 1088 copyright_year = 2020, 1089 configuration_description = "List of ART MTS tests that need root access.", 1090 tests_description = "ART gtests") 1091 1092 self.regen_mts_art_tests_list_user_file(len(mts_test_shards)) 1093 1094 def regen_test_files(self, regen_art_mts): 1095 """Regenerate ART test files. 1096 1097 Args: 1098 regen_art_mts: If true, also regenerate the ART MTS definition. 1099 """ 1100 run_tests = self.enumerate_run_tests() 1101 1102 # Create a list of the tests that can currently be built, and for 1103 # which a Blueprint file is to be generated. 1104 buildable_tests = list(filter(self.is_soong_buildable, run_tests)) 1105 1106 # Create a list of the tests that can be built and run 1107 # (successfully). These tests are to be added to ART's 1108 # `TEST_MAPPING` file and also tagged as part of TradeFed's 1109 # `art-target-run-test` test suite via the `test-suite-tag` option 1110 # in their configuration file. 1111 expected_succeeding_tests = list(filter(self.is_tradefed_runnable, 1112 buildable_tests)) 1113 1114 # Regenerate Blueprint files. 1115 # --------------------------- 1116 1117 self.regen_bp_files(run_tests, buildable_tests) 1118 1119 buildable_tests_percentage = int(len(buildable_tests) * 100 / len(run_tests)) 1120 1121 print(f"Generated Blueprint files for {len(buildable_tests)} ART run-tests out of" 1122 f" {len(run_tests)} ({buildable_tests_percentage}%).") 1123 1124 # Regenerate `TEST_MAPPING` file. 1125 # ------------------------------- 1126 1127 # Note: We only include ART run-tests expected to succeed for now. 1128 num_expected_succeeding_tests = len(expected_succeeding_tests) 1129 1130 presubmit_run_tests = set(expected_succeeding_tests).difference(postsubmit_only_tests) 1131 num_presubmit_run_tests = len(presubmit_run_tests) 1132 presubmit_run_tests_percentage = int( 1133 num_presubmit_run_tests * 100 / num_expected_succeeding_tests) 1134 1135 num_mainline_presubmit_run_tests = num_presubmit_run_tests 1136 mainline_presubmit_run_tests_percentage = presubmit_run_tests_percentage 1137 1138 postsubmit_run_tests = set(expected_succeeding_tests).intersection(postsubmit_only_tests) 1139 num_postsubmit_run_tests = len(postsubmit_run_tests) 1140 postsubmit_run_tests_percentage = int( 1141 num_postsubmit_run_tests * 100 / num_expected_succeeding_tests) 1142 1143 self.regen_test_mapping_file(expected_succeeding_tests) 1144 1145 expected_succeeding_tests_percentage = int( 1146 num_expected_succeeding_tests * 100 / len(run_tests)) 1147 1148 num_gtests = len(art_gtest_module_names) 1149 1150 num_presubmit_gtests = len(art_gtest_presubmit_module_names) 1151 presubmit_gtests_percentage = int(num_presubmit_gtests * 100 / num_gtests) 1152 1153 num_mainline_presubmit_gtests = len(art_gtest_mainline_presubmit_module_names) 1154 mainline_presubmit_gtests_percentage = int(num_mainline_presubmit_gtests * 100 / num_gtests) 1155 1156 num_postsubmit_gtests = len(art_gtest_postsubmit_module_names) 1157 postsubmit_gtests_percentage = int(num_postsubmit_gtests * 100 / num_gtests) 1158 1159 print(f"Generated TEST_MAPPING entries for {num_expected_succeeding_tests} ART run-tests out" 1160 f" of {len(run_tests)} ({expected_succeeding_tests_percentage}%):") 1161 for (num_tests, test_kind, tests_percentage, test_group_name) in [ 1162 (num_mainline_presubmit_run_tests, "ART run-tests", mainline_presubmit_run_tests_percentage, 1163 "art-mainline-presubmit"), 1164 (num_mainline_presubmit_run_tests, "ART run-tests", mainline_presubmit_run_tests_percentage, 1165 "mainline-presubmit"), 1166 (num_presubmit_run_tests, "ART run-tests", presubmit_run_tests_percentage, "presubmit"), 1167 (num_postsubmit_run_tests, "ART run-tests", postsubmit_run_tests_percentage, "postsubmit"), 1168 (num_mainline_presubmit_gtests, "ART gtests", mainline_presubmit_gtests_percentage, 1169 "mainline-presubmit"), 1170 (num_presubmit_gtests, "ART gtests", presubmit_gtests_percentage, "presubmit"), 1171 (num_postsubmit_gtests, "ART gtests", postsubmit_gtests_percentage, "postsubmit"), 1172 ]: 1173 print( 1174 f" {num_tests:3d} {test_kind} ({tests_percentage}%) in `{test_group_name}` test group.") 1175 print(""" Note: Tests in `*presubmit` test groups are executed in pre- and 1176 post-submit test runs. Tests in the `postsubmit` test group 1177 are only executed in post-submit test runs.""") 1178 1179 # Regenerate ART MTS definition (optional). 1180 # ----------------------------------------- 1181 1182 if regen_art_mts: 1183 self.regen_art_mts_files(expected_succeeding_tests, self.enumerate_jvmti_cts_tests()) 1184 print(f"Generated ART MTS entries for {num_expected_succeeding_tests} ART run-tests out" 1185 f" of {len(run_tests)} ({expected_succeeding_tests_percentage}%).") 1186 1187def main(): 1188 if "ANDROID_BUILD_TOP" not in os.environ: 1189 logging.error("ANDROID_BUILD_TOP environment variable is empty; did you forget to run `lunch`?") 1190 sys.exit(1) 1191 1192 parser = argparse.ArgumentParser( 1193 formatter_class=argparse.RawDescriptionHelpFormatter, 1194 description=textwrap.dedent("Regenerate some ART test related files."), 1195 epilog=textwrap.dedent("""\ 1196 Regenerate ART run-tests Blueprint files, ART's `TEST_MAPPING` file, and 1197 optionally the ART MTS (Mainline Test Suite) definition. 1198 """)) 1199 parser.add_argument("-m", "--regen-art-mts", help="regenerate the ART MTS definition as well", 1200 action="store_true") 1201 parser.add_argument("-v", "--verbose", help="enable verbose output", action="store_true") 1202 args = parser.parse_args() 1203 1204 if args.verbose: 1205 logging.getLogger().setLevel(logging.DEBUG) 1206 1207 generator = Generator(os.path.join(os.environ["ANDROID_BUILD_TOP"])) 1208 generator.regen_test_files(args.regen_art_mts) 1209 1210 1211if __name__ == "__main__": 1212 main() 1213