diff options
Diffstat (limited to 'test/run-test')
| -rwxr-xr-x | test/run-test | 2112 |
1 files changed, 1069 insertions, 1043 deletions
diff --git a/test/run-test b/test/run-test index dccc9f63e5..f2be1d8b8c 100755 --- a/test/run-test +++ b/test/run-test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env python3 # # Copyright (C) 2007 The Android Open Source Project # @@ -14,1059 +14,1085 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Set up prog to be the path of this script, including following symlinks, -# and set up progdir to be the fully-qualified pathname of its directory. -prog="$0" -args="$@" -while [ -h "${prog}" ]; do - newProg=`/bin/ls -ld "${prog}"` - newProg=`expr "${newProg}" : ".* -> \(.*\)$"` - if expr "x${newProg}" : 'x/' >/dev/null; then - prog="${newProg}" - else - progdir=`dirname "${prog}"` - prog="${progdir}/${newProg}" - fi -done -oldwd=`pwd` -progdir=`dirname "${prog}"` -cd "${progdir}" -progdir=`pwd` -prog="${progdir}"/`basename "${prog}"` -test_dir="test-$$" -if [ -z "$TMPDIR" ]; then - tmp_dir="/tmp/$USER/${test_dir}" -else - tmp_dir="${TMPDIR}/${test_dir}" -fi -checker="${progdir}/../tools/checker/checker.py" -export JAVA="java" -export JAVAC="javac -g -Xlint:-options -source 1.8 -target 1.8" -export RUN="${progdir}/etc/run-test-jar" -export DEX_LOCATION=/data/run-test/${test_dir} - -# ANDROID_BUILD_TOP is not set in a build environment. -if [ -z "$ANDROID_BUILD_TOP" ]; then - export ANDROID_BUILD_TOP=$oldwd -fi - -# OUT_DIR defaults to out, and may be relative to $ANDROID_BUILD_TOP. -# Convert it to an absolute path, since we cd into the tmp_dir to run the tests. -export OUT_DIR=${OUT_DIR:-out} -if [[ "$OUT_DIR" != /* ]]; then - export OUT_DIR=$ANDROID_BUILD_TOP/$OUT_DIR -fi +import os, sys, glob, re, shutil, subprocess, shlex, resource, atexit + +import default_run as default_run_module + +from default_run import get_target_arch +from importlib.machinery import SourceFileLoader +from inspect import currentframe, getframeinfo, FrameInfo +from pathlib import Path +from shutil import copyfile +from testrunner import env +from typing import Optional, Dict, List +from zipfile import ZipFile + +COLOR = (os.environ.get("LUCI_CONTEXT") == None) # Disable colors on LUCI. +COLOR_BLUE = '\033[94m' if COLOR else '' +COLOR_GREEN = '\033[92m' if COLOR else '' +COLOR_NORMAL = '\033[0m' if COLOR else '' +COLOR_RED = '\033[91m' if COLOR else '' + +# Helper class which allows us to access the environment using syntax sugar. +# E.g. `env.ANDROID_BUILD_TOP` instead of `os.environ["ANDROID_BUILD_TOP"]`. +class Environment: + + def __getattr__(self, name): + return os.environ.get(name) + + def __setattr__(self, name, value): + os.environ[name] = str(value) + + +# Context passed to individual tests to let them customize the behaviour. +class RunTestContext: + + def __init__(self, tmp_dir: Path, target: bool, chroot, dex_location, test_name) -> None: + self.env = Environment() + self.target = target + self.chroot = chroot + self.dex_location = dex_location + self.test_name = test_name + + # Note: The expected path can be modified by the tests. + self.expected_stdout = tmp_dir / "expected-stdout.txt" + self.expected_stderr = tmp_dir / "expected-stderr.txt" + + self.runner: List[str] = ["#!/bin/bash"] + + def echo(self, text): + self.run(f"echo {text} > {test_stdout}") + + def export(self, **env: str) -> None: + self.runner.append("") + for name, value in env.items(): + self.runner.append(f"export {name}={value}") + + # Add "runner" script command. It is not executed now. + # All "runner" commands are executed later via single bash call. + def run(self, cmd: str, check: bool=True, expected_exit_code: int=0, desc:str = None) -> None: + if cmd == "true": + return + cmd_esc = cmd.replace("'", r"'\''") + self.runner.append("") + self.runner.append(f"echo '{COLOR_BLUE}$$ {cmd_esc}{COLOR_NORMAL}'") + self.runner.append(cmd) + + # Check the exit code. + if check: + caller = getframeinfo(currentframe().f_back) # type: ignore + source = "{}:{}".format(Path(caller.filename).name, caller.lineno) + msg = f"{self.test_name} FAILED: [{source}] " + msg += "{} returned exit code ${{exit_code}}.".format(desc or "Command") + if expected_exit_code: + msg += f" Expected {expected_exit_code}." + self.runner.append( + f"exit_code=$?; if [ $exit_code -ne {expected_exit_code} ]; then " + f"echo {COLOR_RED}{msg}{COLOR_NORMAL}; exit 100; " + f"fi; ") + else: + self.runner.append("true; # Ignore previous exit code") + + # Execute the default runner (possibly with modified arguments). + def default_run(self, args, **kwargs): + default_run_module.default_run(self, args, **kwargs) + + +# TODO: Replace with 'def main():' (which might change variables from globals to locals) +if True: + progdir = os.path.dirname(__file__) + oldwd = os.getcwd() + os.chdir(progdir) + test_dir = "test-{}".format(os.getpid()) + TMPDIR = os.environ.get("TMPDIR") + USER = os.environ.get("USER") + PYTHON3 = os.environ.get("PYTHON3") + if not TMPDIR: + tmp_dir = f"/tmp/{USER}/{test_dir}" + else: + tmp_dir = f"{TMPDIR}/{test_dir}" + checker = f"{progdir}/../tools/checker/checker.py" + + ON_VM = os.environ.get("ART_TEST_ON_VM") + SSH_USER = os.environ.get("ART_TEST_SSH_USER") + SSH_HOST = os.environ.get("ART_TEST_SSH_HOST") + SSH_PORT = os.environ.get("ART_TEST_SSH_PORT") + SSH_CMD = os.environ.get("ART_SSH_CMD") + SCP_CMD = os.environ.get("ART_SCP_CMD") + CHROOT = os.environ.get("ART_TEST_CHROOT") + CHROOT_CMD = os.environ.get("ART_CHROOT_CMD") + + def fail(message: str, caller:Optional[FrameInfo]=None): + caller = caller or getframeinfo(currentframe().f_back) # type: ignore + assert caller + source = "{}:{}".format(Path(caller.filename).name, caller.lineno) + print(f"{COLOR_RED}{TEST_NAME} FAILED: [{source}] {message}{COLOR_NORMAL}", + file=sys.stderr) + sys.exit(1) + + def run(cmdline: str, check=True, fail_message=None) -> subprocess.CompletedProcess: + print(f"{COLOR_BLUE}$ {cmdline}{COLOR_NORMAL}", flush=True) + proc = subprocess.run([cmdline], + shell=True, + executable="/bin/bash", + stderr=subprocess.STDOUT) + if (check and proc.returncode != 0): + if fail_message: + # If we have custom fail message, exit without printing the full backtrace. + fail(fail_message, getframeinfo(currentframe().f_back)) # type: ignore + raise Exception(f"Command failed (exit code {proc.returncode})") + return proc + + def export(env: str, value: str) -> None: + os.environ[env] = value + globals()[env] = value + + def error(msg) -> None: + print(msg, file=sys.stderr, flush=True) + + # ANDROID_BUILD_TOP is not set in a build environment. + ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP") + if not ANDROID_BUILD_TOP: + export("ANDROID_BUILD_TOP", oldwd) + + export("JAVA", "java") + export("JAVAC", "javac -g -Xlint:-options -source 1.8 -target 1.8") + export("PYTHON3", + f"{ANDROID_BUILD_TOP}/prebuilts/build-tools/path/linux-x86/python3") + export("RUN", f"{PYTHON3} {progdir}/etc/run-test-jar") + export("DEX_LOCATION", f"/data/run-test/{test_dir}") + + # OUT_DIR defaults to out, and may be relative to ANDROID_BUILD_TOP. + # Convert it to an absolute path, since we cd into the tmp_dir to run the tests. + OUT_DIR = os.environ.get("OUT_DIR", "") + export("OUT_DIR", OUT_DIR or "out") + if not OUT_DIR.startswith("/"): + export("OUT_DIR", f"{ANDROID_BUILD_TOP}/{OUT_DIR}") # ANDROID_HOST_OUT is not set in a build environment. -if [ -z "$ANDROID_HOST_OUT" ]; then - export ANDROID_HOST_OUT=${OUT_DIR}/host/linux-x86 -fi - -host_lib_root=${ANDROID_HOST_OUT} -chroot= -info="info.txt" -run="run" -expected_stdout="expected-stdout.txt" -expected_stderr="expected-stderr.txt" -check_cmd="check" -test_stdout="test-stdout.txt" -test_stderr="test-stderr.txt" -cfg_output="graph.cfg" -strace_output="strace-output.txt" -lib="libartd.so" -testlib="arttestd" -run_args=(--quiet) - -quiet="no" -debuggable="no" -prebuild_mode="yes" -target_mode="yes" -dev_mode="no" -create_runner="no" -update_mode="no" -debug_mode="no" -relocate="no" -runtime="art" -usage="no" -suffix64="" -trace="false" -trace_stream="false" -basic_verify="false" -gc_verify="false" -gc_stress="false" -jvmti_trace_stress="false" -jvmti_field_stress="false" -jvmti_step_stress="false" -jvmti_redefine_stress="false" -strace="false" -always_clean="no" -never_clean="no" -have_image="yes" -android_root="/system" -bisection_search="no" -timeout="" -suspend_timeout="500000" -run_optimizing="false" -dump_cfg="false" -dump_cfg_path="" -# To cause tests to fail fast, limit the file sizes created by dx, dex2oat and -# ART output to approximately 128MB. This should be more than sufficient -# for any test while still catching cases of runaway output. -# Set a hard limit to encourage ART developers to increase the ulimit here if -# needed to support a test case rather than resetting the limit in the run -# script for the particular test in question. Adjust this if needed for -# particular configurations. -file_ulimit=128000 - - -while true; do - if [ "x$1" = "x--host" ]; then - target_mode="no" - DEX_LOCATION=$tmp_dir - run_args+=(--host) - shift - elif [ "x$1" = "x--quiet" ]; then - quiet="yes" - shift - elif [ "x$1" = "x--use-java-home" ]; then - if [ -n "${JAVA_HOME}" ]; then - export JAVA="${JAVA_HOME}/bin/java" - export JAVAC="${JAVA_HOME}/bin/javac -g" - else - echo "Passed --use-java-home without JAVA_HOME variable set!" - usage="yes" - fi - shift - elif [ "x$1" = "x--jvm" ]; then - target_mode="no" - DEX_LOCATION="$tmp_dir" - runtime="jvm" - prebuild_mode="no" - run_args+=(--jvm) - shift - elif [ "x$1" = "x-O" ]; then - lib="libart.so" - testlib="arttest" - run_args+=(-O) - shift - elif [ "x$1" = "x--dalvik" ]; then - lib="libdvm.so" - runtime="dalvik" - shift - elif [ "x$1" = "x--no-image" ]; then - have_image="no" - shift - elif [ "x$1" = "x--relocate" ]; then - relocate="yes" - shift - elif [ "x$1" = "x--no-relocate" ]; then - relocate="no" - shift - elif [ "x$1" = "x--prebuild" ]; then - run_args+=(--prebuild) - prebuild_mode="yes" - shift; - elif [ "x$1" = "x--compact-dex-level" ]; then - option="$1" - shift - run_args+=("$option" "$1") - shift; - elif [ "x$1" = "x--strip-dex" ]; then - run_args+=(--strip-dex) - shift; - elif [ "x$1" = "x--debuggable" ]; then - run_args+=(-Xcompiler-option --debuggable) - debuggable="yes" - shift; - elif [ "x$1" = "x--no-prebuild" ]; then - run_args+=(--no-prebuild) - prebuild_mode="no" - shift; - elif [ "x$1" = "x--gcverify" ]; then - basic_verify="true" - gc_verify="true" - shift - elif [ "x$1" = "x--gcstress" ]; then - basic_verify="true" - gc_stress="true" - shift - elif [ "x$1" = "x--jvmti-step-stress" ]; then - jvmti_step_stress="true" - shift - elif [ "x$1" = "x--jvmti-redefine-stress" ]; then - jvmti_redefine_stress="true" - shift - elif [ "x$1" = "x--jvmti-field-stress" ]; then - jvmti_field_stress="true" - shift - elif [ "x$1" = "x--jvmti-trace-stress" ]; then - jvmti_trace_stress="true" - shift - elif [ "x$1" = "x--suspend-timeout" ]; then - shift - suspend_timeout="$1" - shift - elif [ "x$1" = "x--image" ]; then - shift - image="$1" - run_args+=(--image "$image") - shift - elif [ "x$1" = "x-Xcompiler-option" ]; then - shift - option="$1" - run_args+=(-Xcompiler-option "$option") - shift - elif [ "x$1" = "x--runtime-option" ]; then - shift - option="$1" - run_args+=(--runtime-option "$option") - shift - elif [ "x$1" = "x--gdb-arg" ]; then - shift - gdb_arg="$1" - run_args+=(--gdb-arg "$gdb_arg") - shift - elif [ "x$1" = "x--gdb-dex2oat-args" ]; then - shift - gdb_dex2oat_args="$1" - run_args+=(--gdb-dex2oat-args "$gdb_dex2oat_args") - shift - elif [ "x$1" = "x--debug" ]; then - run_args+=(--debug) - shift - elif [ "x$1" = "x--debug-wrap-agent" ]; then - run_args+=(--debug-wrap-agent) - shift - elif [ "x$1" = "x--with-agent" ]; then - shift - option="$1" - run_args+=(--with-agent "$1") - shift - elif [ "x$1" = "x--debug-agent" ]; then - shift - option="$1" - run_args+=(--debug-agent "$1") - shift - elif [ "x$1" = "x--dump-cfg" ]; then - shift - dump_cfg="true" - dump_cfg_path="$1" - shift - elif [ "x$1" = "x--gdb" ]; then - run_args+=(--gdb) - dev_mode="yes" - shift - elif [ "x$1" = "x--gdb-dex2oat" ]; then - run_args+=(--gdb-dex2oat) - dev_mode="yes" - shift - elif [ "x$1" = "x--gdbserver-bin" ]; then - shift - run_args+=(--gdbserver-bin "$1") - shift - elif [ "x$1" = "x--gdbserver-port" ]; then - shift - run_args+=(--gdbserver-port "$1") - shift - elif [ "x$1" = "x--gdbserver" ]; then - run_args+=(--gdbserver) - dev_mode="yes" - shift - elif [ "x$1" = "x--strace" ]; then - strace="yes" - run_args+=(--invoke-with strace --invoke-with -o --invoke-with "$tmp_dir/$strace_output") - timeout="${timeout:-1800}" - shift - elif [ "x$1" = "x--zygote" ]; then - run_args+=(--zygote) - shift - elif [ "x$1" = "x--interpreter" ]; then - run_args+=(--interpreter) - shift - elif [ "x$1" = "x--jit" ]; then - run_args+=(--jit) - shift - elif [ "x$1" = "x--baseline" ]; then - run_args+=(--baseline) - shift - elif [ "x$1" = "x--optimizing" ]; then - run_optimizing="true" - shift - elif [ "x$1" = "x--no-verify" ]; then - run_args+=(--no-verify) - shift - elif [ "x$1" = "x--verify-soft-fail" ]; then - run_args+=(--verify-soft-fail) - shift - elif [ "x$1" = "x--no-optimize" ]; then - run_args+=(--no-optimize) - shift - elif [ "x$1" = "x--no-precise" ]; then - run_args+=(--no-precise) - shift - elif [ "x$1" = "x--external-log-tags" ]; then - run_args+=(--external-log-tags) - shift - elif [ "x$1" = "x--invoke-with" ]; then - shift - what="$1" - if [ "x$what" = "x" ]; then - echo "$0 missing argument to --invoke-with" 1>&2 - usage="yes" - break - fi - run_args+=(--invoke-with "${what}") - shift - elif [ "x$1" = "x--create-runner" ]; then - run_args+=(--create-runner --dry-run) - dev_mode="yes" - never_clean="yes" - create_runner="yes" - shift - elif [ "x$1" = "x--dev" ]; then - run_args+=(--dev) - dev_mode="yes" - shift - elif [ "x$1" = "x--temp-path" ]; then - shift - tmp_dir=$1 - if [ "x$tmp_dir" = "x" ]; then - echo "$0 missing argument to --temp-path" 1>&2 - usage="yes" - break - fi - shift - elif [ "x$1" = "x--chroot" ]; then - shift - if [ "x$1" = "x" ]; then - echo "$0 missing argument to --chroot" 1>&2 - usage="yes" - break - fi - chroot="$1" - run_args+=(--chroot "$1") - shift - elif [ "x$1" = "x--simpleperf" ]; then - run_args+=(--simpleperf) - shift - elif [ "x$1" = "x--android-root" ]; then - shift - if [ "x$1" = "x" ]; then - echo "$0 missing argument to --android-root" 1>&2 - usage="yes" - break - fi - android_root="$1" - run_args+=(--android-root "$1") - shift - elif [ "x$1" = "x--android-art-root" ]; then - shift - if [ "x$1" = "x" ]; then - echo "$0 missing argument to --android-art-root" 1>&2 - usage="yes" - break - fi - run_args+=(--android-art-root "$1") - shift - elif [ "x$1" = "x--android-tzdata-root" ]; then - shift - if [ "x$1" = "x" ]; then - echo "$0 missing argument to --android-tzdata-root" 1>&2 - usage="yes" - break - fi - run_args+=(--android-tzdata-root "$1") - shift - elif [ "x$1" = "x--update" ]; then - update_mode="yes" - shift - elif [ "x$1" = "x--help" ]; then - usage="yes" - shift - elif [ "x$1" = "x--64" ]; then - run_args+=(--64) - suffix64="64" - shift - elif [ "x$1" = "x--bionic" ]; then - # soong linux_bionic builds are 64bit only. - run_args+=(--bionic --host --64) - suffix64="64" - target_mode="no" - DEX_LOCATION=$tmp_dir - host_lib_root=$OUT_DIR/soong/host/linux_bionic-x86 - shift - elif [ "x$1" = "x--runtime-extracted-zipapex" ]; then - shift - # TODO Should we allow the java.library.path to search the zipapex too? - # Not needed at the moment and adding it will be complicated so for now - # we'll ignore this. - run_args+=(--host --runtime-extracted-zipapex "$1") - target_mode="no" - DEX_LOCATION=$tmp_dir - shift - elif [ "x$1" = "x--runtime-zipapex" ]; then - shift - # TODO Should we allow the java.library.path to search the zipapex too? - # Not needed at the moment and adding it will be complicated so for now - # we'll ignore this. - run_args+=(--host --runtime-zipapex "$1") - target_mode="no" - DEX_LOCATION=$tmp_dir - # apex_payload.zip is quite large we need a high enough ulimit to - # extract it. 512mb should be good enough. - file_ulimit=512000 - shift - elif [ "x$1" = "x--timeout" ]; then - shift - if [ "x$1" = "x" ]; then - echo "$0 missing argument to --timeout" 1>&2 - usage="yes" - break - fi - timeout="$1" - shift - elif [ "x$1" = "x--trace" ]; then - trace="true" - shift - elif [ "x$1" = "x--stream" ]; then - trace_stream="true" - shift - elif [ "x$1" = "x--always-clean" ]; then - always_clean="yes" - shift - elif [ "x$1" = "x--never-clean" ]; then - never_clean="yes" - shift - elif [ "x$1" = "x--dex2oat-swap" ]; then - run_args+=(--dex2oat-swap) - shift - elif [ "x$1" = "x--instruction-set-features" ]; then - shift - run_args+=(--instruction-set-features "$1") - shift - elif [ "x$1" = "x--bisection-search" ]; then - bisection_search="yes" - shift - elif [ "x$1" = "x--vdex" ]; then - run_args+=(--vdex) - shift - elif [ "x$1" = "x--dm" ]; then - run_args+=(--dm) - shift - elif [ "x$1" = "x--vdex-filter" ]; then - shift - filter=$1 - run_args+=(--vdex-filter "$filter") - shift - elif [ "x$1" = "x--random-profile" ]; then - run_args+=(--random-profile) - shift - elif [ "x$1" = "x--dex2oat-jobs" ]; then - shift - run_args+=(-Xcompiler-option "-j$1") - shift - elif expr "x$1" : "x--" >/dev/null 2>&1; then - echo "unknown $0 option: $1" 1>&2 - usage="yes" + ANDROID_HOST_OUT = os.environ.get("ANDROID_HOST_OUT") + if not ANDROID_HOST_OUT: + export("ANDROID_HOST_OUT", f"{OUT_DIR}/host/linux-x86") + + host_lib_root = ANDROID_HOST_OUT + chroot = "" + info = "info.txt" + run_cmd = "run" + test_stdout = "test-stdout.txt" + test_stderr = "test-stderr.txt" + cfg_output = "graph.cfg" + strace_output = "strace-output.txt" + lib = "libartd.so" + testlib = "arttestd" + run_args = [] + run_checker = "no" + + quiet = "no" + debuggable = "no" + prebuild_mode = "yes" + target_mode = "yes" + dev_mode = "no" + create_runner = "no" + update_mode = "no" + debug_mode = "no" + relocate = "no" + runtime = "art" + usage = "no" + suffix64 = "" + trace = "false" + trace_stream = "false" + basic_verify = "false" + gc_verify = "false" + gc_stress = "false" + jvmti_trace_stress = "false" + jvmti_field_stress = "false" + jvmti_step_stress = "false" + jvmti_redefine_stress = "false" + strace = "false" + always_clean = "no" + never_clean = "no" + have_image = "yes" + android_root = "/system" + bisection_search = "no" + timeout = "" + suspend_timeout = "500000" + run_optimizing = "false" + dump_cfg = "false" + dump_cfg_path = "" + # To cause tests to fail fast, limit the file sizes created by dx, dex2oat and + # ART output to approximately 128MB. This should be more than sufficient + # for any test while still catching cases of runaway output. + # Set a hard limit to encourage ART developers to increase the ulimit here if + # needed to support a test case rather than resetting the limit in the run + # script for the particular test in question. Adjust this if needed for + # particular configurations. + file_ulimit = 128000 + + args = list(sys.argv) + arg = args[0] + + def shift(): + global arg + args.pop(0) + arg = args[0] if args else "" + + shift() + + while True: + if arg == "--host": + target_mode = "no" + DEX_LOCATION = tmp_dir + run_args += ["--host"] + os.environ["RUN_MODE"] = "host" + shift() + elif arg == "--quiet": + quiet = "yes" + shift() + elif arg == "--use-java-home": + JAVA_HOME = os.environ.get("JAVA_HOME") + if JAVA_HOME: + export("JAVA", f"{JAVA_HOME}/bin/java") + export("JAVAC", f"{JAVA_HOME}/bin/javac -g") + else: + error("Passed --use-java-home without JAVA_HOME variable set!") + usage = "yes" + shift() + elif arg == "--jvm": + target_mode = "no" + DEX_LOCATION = tmp_dir + runtime = "jvm" + prebuild_mode = "no" + run_args += ["--jvm"] + shift() + elif arg == "-O": + lib = "libart.so" + testlib = "arttest" + run_args += ["-O"] + shift() + elif arg == "--dalvik": + lib = "libdvm.so" + runtime = "dalvik" + shift() + elif arg == "--no-image": + have_image = "no" + shift() + elif arg == "--relocate": + relocate = "yes" + shift() + elif arg == "--no-relocate": + relocate = "no" + shift() + elif arg == "--prebuild": + run_args += ["--prebuild"] + prebuild_mode = "yes" + shift() + elif arg == "--compact-dex-level": + option = arg + shift() + run_args += [f'"{option}" "{arg}"'] + shift() + elif arg == "--strip-dex": + run_args += ["--strip-dex"] + shift() + elif arg == "--debuggable": + run_args += ["-Xcompiler-option --debuggable"] + debuggable = "yes" + shift() + elif arg == "--no-prebuild": + run_args += ["--no-prebuild"] + prebuild_mode = "no" + shift() + elif arg == "--gcverify": + basic_verify = "true" + gc_verify = "true" + shift() + elif arg == "--gcstress": + basic_verify = "true" + gc_stress = "true" + shift() + elif arg == "--jvmti-step-stress": + jvmti_step_stress = "true" + os.environ["JVMTI_STEP_STRESS"] = "true" + shift() + elif arg == "--jvmti-redefine-stress": + jvmti_redefine_stress = "true" + os.environ["JVMTI_REDEFINE_STRESS"] = "true" + shift() + elif arg == "--jvmti-field-stress": + jvmti_field_stress = "true" + os.environ["JVMTI_FIELD_STRESS"] = "true" + shift() + elif arg == "--jvmti-trace-stress": + jvmti_trace_stress = "true" + os.environ["JVMTI_TRACE_STRESS"] = "true" + shift() + elif arg == "--suspend-timeout": + shift() + suspend_timeout = arg + shift() + elif arg == "--image": + shift() + image = arg + run_args += [f'--image "{image}"'] + shift() + elif arg == "-Xcompiler-option": + shift() + option = arg + run_args += [f'-Xcompiler-option "{option}"'] + shift() + elif arg == "--runtime-option": + shift() + option = arg + run_args += [f'--runtime-option "{option}"'] + shift() + elif arg == "--gdb-arg": + shift() + gdb_arg = arg + run_args += [f'--gdb-arg "{gdb_arg}"'] + shift() + elif arg == "--gdb-dex2oat-args": + shift() + gdb_dex2oat_args = arg + run_args += ['--gdb-dex2oat-args "{gdb_dex2oat_args}"'] + shift() + elif arg == "--debug": + run_args += ["--debug"] + shift() + elif arg == "--debug-wrap-agent": + run_args += ["--debug-wrap-agent"] + shift() + elif arg == "--with-agent": + shift() + option = arg + run_args += [f'--with-agent "{arg}"'] + shift() + elif arg == "--debug-agent": + shift() + option = arg + run_args += [f'--debug-agent "{arg}"'] + shift() + elif arg == "--dump-cfg": + shift() + dump_cfg = "true" + dump_cfg_path = arg + shift() + elif arg == "--gdb": + run_args += ["--gdb"] + dev_mode = "yes" + shift() + elif arg == "--gdb-dex2oat": + run_args += ["--gdb-dex2oat"] + dev_mode = "yes" + shift() + elif arg == "--gdbserver-bin": + shift() + run_args += [f'--gdbserver-bin "{arg}"'] + shift() + elif arg == "--gdbserver-port": + shift() + run_args += [f'--gdbserver-port "{arg}"'] + shift() + elif arg == "--gdbserver": + run_args += ["--gdbserver"] + dev_mode = "yes" + shift() + elif arg == "--strace": + strace = "yes" + run_args += [ + f'--invoke-with=strace --invoke-with=-o --invoke-with="{tmp_dir}/{strace_output}"' + ] + timeout = timeout or "1800" + shift() + elif arg == "--zygote": + run_args += ["--zygote"] + shift() + elif arg == "--interpreter": + run_args += ["--interpreter"] + shift() + elif arg == "--jit": + run_args += ["--jit"] + shift() + elif arg == "--baseline": + run_args += ["--baseline"] + shift() + elif arg == "--optimizing": + run_optimizing = "true" + shift() + elif arg == "--no-verify": + run_args += ["--no-verify"] + shift() + elif arg == "--verify-soft-fail": + run_args += ["--verify-soft-fail"] + os.environ["VERIFY_SOFT_FAIL"] = "true" + shift() + elif arg == "--no-optimize": + run_args += ["--no-optimize"] + shift() + elif arg == "--no-precise": + run_args += ["--no-precise"] + shift() + elif arg.startswith("--android-log-tags"): + run_args += [arg] + shift() + elif arg == "--external-log-tags": + run_args += ["--external-log-tags"] + shift() + elif arg == "--invoke-with": + shift() + what = arg + if not arg: + error("missing argument to --invoke-with") + usage = "yes" + break + run_args += [f'--invoke-with "{what}"'] + shift() + elif arg == "--create-runner": + run_args += ["--create-runner --dry-run"] + dev_mode = "yes" + never_clean = "yes" + create_runner = "yes" + shift() + elif arg == "--dev": + dev_mode = "yes" + shift() + elif arg == "--temp-path": + shift() + if not arg: + error("missing argument to --temp-path") + usage = "yes" + break + shift() + elif arg == "--chroot": + shift() + if not arg: + error("missing argument to --chroot") + usage = "yes" + break + chroot = arg + run_args += [f'--chroot "{arg}"'] + shift() + elif arg == "--simpleperf": + run_args += ["--simpleperf"] + shift() + elif arg == "--android-root": + shift() + if not arg: + error("missing argument to --android-root") + usage = "yes" + break + android_root = arg + run_args += [f'--android-root "{arg}"'] + shift() + elif arg == "--android-art-root": + shift() + if not arg: + error("missing argument to --android-art-root") + usage = "yes" break - else + run_args += [f'--android-art-root "{arg}"'] + shift() + elif arg == "--android-tzdata-root": + shift() + if not arg: + error("missing argument to --android-tzdata-root") + usage = "yes" break - fi -done + run_args += [f'--android-tzdata-root "{arg}"'] + shift() + elif arg == "--update": + update_mode = "yes" + shift() + elif arg == "--help": + usage = "yes" + shift() + elif arg == "--64": + run_args += ["--64"] + suffix64 = "64" + shift() + elif arg == "--bionic": + # soong linux_bionic builds are 64bit only. + run_args += ["--bionic --host --64"] + suffix64 = "64" + target_mode = "no" + DEX_LOCATION = tmp_dir + host_lib_root = f"{OUT_DIR}/soong/host/linux_bionic-x86" + shift() + elif arg == "--runtime-extracted-zipapex": + shift() + # TODO Should we allow the java.library.path to search the zipapex too? + # Not needed at the moment and adding it will be complicated so for now + # we'll ignore this. + run_args += [f'--host --runtime-extracted-zipapex "{arg}"'] + target_mode = "no" + DEX_LOCATION = tmp_dir + shift() + elif arg == "--runtime-zipapex": + shift() + # TODO Should we allow the java.library.path to search the zipapex too? + # Not needed at the moment and adding it will be complicated so for now + # we'll ignore this. + run_args += [f'--host --runtime-zipapex "{arg}"'] + target_mode = "no" + DEX_LOCATION = tmp_dir + # apex_payload.zip is quite large we need a high enough ulimit to + # extract it. 512mb should be good enough. + file_ulimit = 512000 + shift() + elif arg == "--timeout": + shift() + if not arg: + error("missing argument to --timeout") + usage = "yes" + break + timeout = arg + shift() + elif arg == "--trace": + trace = "true" + shift() + elif arg == "--stream": + trace_stream = "true" + shift() + elif arg == "--always-clean": + always_clean = "yes" + shift() + elif arg == "--never-clean": + never_clean = "yes" + shift() + elif arg == "--dex2oat-swap": + run_args += ["--dex2oat-swap"] + shift() + elif arg == "--instruction-set-features": + shift() + run_args += [f'--instruction-set-features "{arg}"'] + shift() + elif arg == "--bisection-search": + bisection_search = "yes" + shift() + elif arg == "--vdex": + run_args += ["--vdex"] + shift() + elif arg == "--dm": + run_args += ["--dm"] + shift() + elif arg == "--vdex-filter": + shift() + filter = arg + run_args += ['--vdex-filter "{filter}"'] + shift() + elif arg == "--random-profile": + run_args += ["--random-profile"] + shift() + elif arg == "--dex2oat-jobs": + shift() + run_args += [f'-Xcompiler-option "-j{arg}"'] + shift() + elif arg.startswith("--"): + error(f"unknown option: {arg}") + usage = "yes" + break + else: + break + + export("DEX_LOCATION", DEX_LOCATION) -if [ "$usage" = "no" -a "x$1" = "x" ]; then - echo "missing test to run" 1>&2 - usage="yes" -fi + if usage == "no" and not arg: + error("missing test to run") + usage = "yes" # The DEX_LOCATION with the chroot prefix, if any. -chroot_dex_location="$chroot$DEX_LOCATION" - -# Allocate file descriptor real_stderr and redirect it to the shell's error -# output (fd 2). -if [ ${BASH_VERSINFO[1]} -ge 4 ] && [ ${BASH_VERSINFO[2]} -ge 1 ]; then - exec {real_stderr}>&2 -else - # In bash before version 4.1 we need to do a manual search for free file - # descriptors. - FD=3 - while [ -e /dev/fd/$FD ]; do FD=$((FD + 1)); done - real_stderr=$FD - eval "exec ${real_stderr}>&2" -fi -if [ "$quiet" = "yes" ]; then - # Force the default standard output and error to go to /dev/null so we will - # not print them. - exec 1>/dev/null - exec 2>/dev/null -fi - -function err_echo() { - echo "$@" 1>&${real_stderr} -} - -# tmp_dir may be relative, resolve. -# -# Cannot use realpath, as it does not exist on Mac. -# Cannot use a simple "cd", as the path might not be created yet. -# Cannot use readlink -m, as it does not exist on Mac. -# Fallback to nuclear option: -noncanonical_tmp_dir=$tmp_dir -tmp_dir="`cd $oldwd ; python3 -c "import os; import sys; sys.stdout.write(os.path.realpath('$tmp_dir'))"`" -if [ -z $tmp_dir ] ; then - err_echo "Failed to resolve $tmp_dir" - exit 1 -fi -mkdir -p $tmp_dir - -# Add thread suspend timeout flag -if [ ! "$runtime" = "jvm" ]; then - run_args+=(--runtime-option "-XX:ThreadSuspendTimeout=$suspend_timeout") -fi - -if [ "$basic_verify" = "true" ]; then - # Set HspaceCompactForOOMMinIntervalMs to zero to run hspace compaction for OOM more frequently in tests. - run_args+=(--runtime-option -Xgc:preverify --runtime-option -Xgc:postverify --runtime-option -XX:HspaceCompactForOOMMinIntervalMs=0) -fi -if [ "$gc_verify" = "true" ]; then - run_args+=(--runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc) -fi -if [ "$gc_stress" = "true" ]; then - run_args+=(--gc-stress --runtime-option -Xgc:gcstress --runtime-option -Xms2m --runtime-option -Xmx16m) -fi -if [ "$jvmti_redefine_stress" = "true" ]; then - run_args+=(--no-app-image --jvmti-redefine-stress) -fi -if [ "$jvmti_step_stress" = "true" ]; then - run_args+=(--no-app-image --jvmti-step-stress) -fi -if [ "$jvmti_field_stress" = "true" ]; then - run_args+=(--no-app-image --jvmti-field-stress) -fi -if [ "$jvmti_trace_stress" = "true" ]; then - run_args+=(--no-app-image --jvmti-trace-stress) -fi -if [ "$trace" = "true" ]; then - run_args+=(--runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000) - if [ "$trace_stream" = "true" ]; then - # Streaming mode uses the file size as the buffer size. So output gets really large. Drop - # the ability to analyze the file and just write to /dev/null. - run_args+=(--runtime-option -Xmethod-trace-file:/dev/null) - # Enable streaming mode. - run_args+=(--runtime-option -Xmethod-trace-stream) - else - run_args+=(--runtime-option "-Xmethod-trace-file:${DEX_LOCATION}/trace.bin") - fi -elif [ "$trace_stream" = "true" ]; then - err_echo "Cannot use --stream without --trace." - exit 1 -fi -if [ -n "$timeout" ]; then - run_args+=(--timeout "$timeout") -fi + chroot_dex_location = f"{chroot}{DEX_LOCATION}" + + # tmp_dir may be relative, resolve. + os.chdir(oldwd) + tmp_dir = os.path.realpath(tmp_dir) + os.chdir(progdir) + if not tmp_dir: + error(f"Failed to resolve {tmp_dir}") + sys.exit(1) + os.makedirs(tmp_dir, exist_ok=True) + + # Add thread suspend timeout flag + if runtime != "jvm": + run_args += [ + f'--runtime-option "-XX:ThreadSuspendTimeout={suspend_timeout}"' + ] + + if basic_verify == "true": + # Set HspaceCompactForOOMMinIntervalMs to zero to run hspace compaction for OOM more frequently in tests. + run_args += [ + "--runtime-option -Xgc:preverify --runtime-option -Xgc:postverify " + "--runtime-option -XX:HspaceCompactForOOMMinIntervalMs=0" + ] + if gc_verify == "true": + run_args += [ + "--runtime-option -Xgc:preverify_rosalloc --runtime-option " + "-Xgc:postverify_rosalloc" + ] + if gc_stress == "true": + run_args += [ + "--gc-stress --runtime-option -Xgc:gcstress --runtime-option -Xms2m " + "--runtime-option -Xmx16m" + ] + if jvmti_redefine_stress == "true": + run_args += ["--no-app-image --jvmti-redefine-stress"] + if jvmti_step_stress == "true": + run_args += ["--no-app-image --jvmti-step-stress"] + if jvmti_field_stress == "true": + run_args += ["--no-app-image --jvmti-field-stress"] + if jvmti_trace_stress == "true": + run_args += ["--no-app-image --jvmti-trace-stress"] + if trace == "true": + run_args += [ + "--runtime-option -Xmethod-trace --runtime-option " + "-Xmethod-trace-file-size:2000000" + ] + if trace_stream == "true": + # Streaming mode uses the file size as the buffer size. So output gets really large. Drop + # the ability to analyze the file and just write to /dev/null. + run_args += ["--runtime-option -Xmethod-trace-file:/dev/null"] + # Enable streaming mode. + run_args += ["--runtime-option -Xmethod-trace-stream"] + else: + run_args += [ + f'--runtime-option "-Xmethod-trace-file:{DEX_LOCATION}/trace.bin"' + ] + elif trace_stream == "true": + error("Cannot use --stream without --trace.") + sys.exit(1) + if timeout: + run_args += [f'--timeout "{timeout}"'] # Most interesting target architecture variables are Makefile variables, not environment variables. -# Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name. -function guess_target_arch_name() { - # Check whether this is a device with native bridge. Currently this is hardcoded - # to x86 + arm. - local guess_path=$chroot/system/framework/art_boot_images - local x86_arm=`adb shell ls ${guess_path} | sort | grep -E '^(arm|x86)$'` - # Collapse line-breaks into spaces - x86_arm=$(echo $x86_arm) - if [ "x$x86_arm" = "xarm x86" ] ; then - err_echo "Native-bridge configuration detected." - # We only support the main arch for tests. - if [ "x${suffix64}" = "x64" ]; then - target_arch_name="" - else - target_arch_name=x86 - fi - else - local grep32bit=`adb shell ls ${guess_path} | grep -E '^(arm|x86)$'` - local grep64bit=`adb shell ls ${guess_path} | grep -E '^(arm64|x86_64)$'` - if [ "x${suffix64}" = "x64" ]; then - target_arch_name=${grep64bit} - else - target_arch_name=${grep32bit} - fi - fi -} - -function guess_host_arch_name() { - if [ "x${suffix64}" = "x64" ]; then - host_arch_name="x86_64" - else - host_arch_name="x86" - fi -} - -if [ "$target_mode" = "no" ]; then - if [ "$runtime" = "jvm" ]; then - if [ "$prebuild_mode" = "yes" ]; then - err_echo "--prebuild with --jvm is unsupported" - exit 1 - fi - else - # ART/Dalvik host mode. - if [ -n "$chroot" ]; then - err_echo "--chroot with --host is unsupported" - exit 1 - fi - fi -fi - -if [ ! "$runtime" = "jvm" ]; then - run_args+=(--lib "$lib") -fi - -if [ "$runtime" = "dalvik" ]; then - if [ "$target_mode" = "no" ]; then - framework="${ANDROID_PRODUCT_OUT}/system/framework" - bpath="${framework}/core-icu4j.jar:${framework}/core-libart.jar:${framework}/core-oj.jar:${framework}/conscrypt.jar:${framework}/okhttp.jar:${framework}/bouncycastle.jar:${framework}/ext.jar" - run_args+=(--boot --runtime-option "-Xbootclasspath:${bpath}") - else - true # defaults to using target BOOTCLASSPATH - fi -elif [ "$runtime" = "art" ]; then - if [ "$target_mode" = "no" ]; then - guess_host_arch_name - run_args+=(--boot "${ANDROID_HOST_OUT}/apex/art_boot_images/javalib/boot.art") - run_args+=(--runtime-option "-Djava.library.path=${host_lib_root}/lib${suffix64}:${host_lib_root}/nativetest${suffix64}") - else - guess_target_arch_name - # Note that libarttest(d).so and other test libraries that depend on ART - # internal libraries must not be in this path for JNI libraries - they - # need to be loaded through LD_LIBRARY_PATH and - # NATIVELOADER_DEFAULT_NAMESPACE_LIBS instead. - run_args+=(--runtime-option "-Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}") - run_args+=(--boot "/system/framework/art_boot_images/boot.art") - fi - if [ "$relocate" = "yes" ]; then - run_args+=(--relocate) - else - run_args+=(--no-relocate) - fi -elif [ "$runtime" = "jvm" ]; then +# Try to map the suffix64 flag and what we find in {ANDROID_PRODUCT_OUT}/data/art-test to an architecture name. + + def guess_target_arch_name(): + return get_target_arch(suffix64 == "64") + + def guess_host_arch_name(): + if suffix64 == "64": + return "x86_64" + else: + return "x86" + + if target_mode == "no": + if runtime == "jvm": + if prebuild_mode == "yes": + error("--prebuild with --jvm is unsupported") + sys.exit(1) + else: + # ART/Dalvik host mode. + if chroot: + error("--chroot with --host is unsupported") + sys.exit(1) + + if runtime != "jvm": + run_args += [f'--lib "{lib}"'] + + ANDROID_PRODUCT_OUT = os.environ.get("ANDROID_PRODUCT_OUT") + if runtime == "dalvik": + if target_mode == "no": + framework = f"{ANDROID_PRODUCT_OUT}/system/framework" + bpath = f"{framework}/core-icu4j.jar:{framework}/core-libart.jar:{framework}/core-oj.jar:{framework}/conscrypt.jar:{framework}/okhttp.jar:{framework}/bouncycastle.jar:{framework}/ext.jar" + run_args += [f'--boot --runtime-option "-Xbootclasspath:{bpath}"'] + else: + pass # defaults to using target BOOTCLASSPATH + elif runtime == "art": + if target_mode == "no": + host_arch_name = guess_host_arch_name() + run_args += [ + f'--boot "{ANDROID_HOST_OUT}/apex/art_boot_images/javalib/boot.art"' + ] + run_args += [ + f'--runtime-option "-Djava.library.path={host_lib_root}/lib{suffix64}:{host_lib_root}/nativetest{suffix64}"' + ] + else: + target_arch_name = guess_target_arch_name() + # Note that libarttest(d).so and other test libraries that depend on ART + # internal libraries must not be in this path for JNI libraries - they + # need to be loaded through LD_LIBRARY_PATH and + # NATIVELOADER_DEFAULT_NAMESPACE_LIBS instead. + run_args += [ + f'--runtime-option "-Djava.library.path=/data/nativetest{suffix64}/art/{target_arch_name}"' + ] + run_args += ['--boot "/system/framework/art_boot_images/boot.art"'] + if relocate == "yes": + run_args += ["--relocate"] + else: + run_args += ["--no-relocate"] + elif runtime == "jvm": # TODO: Detect whether the host is 32-bit or 64-bit. - run_args+=(--runtime-option "-Djava.library.path=${ANDROID_HOST_OUT}/lib64:${ANDROID_HOST_OUT}/nativetest64") -fi - -if [ "$have_image" = "no" ]; then - if [ "$runtime" != "art" ]; then - err_echo "--no-image is only supported on the art runtime" - exit 1 - fi - run_args+=(--no-image) -fi - -if [ "$create_runner" = "yes" -a "$target_mode" = "yes" ]; then - err_echo "--create-runner does not function for non --host tests" - usage="yes" -fi - -if [ "$dev_mode" = "yes" -a "$update_mode" = "yes" ]; then - err_echo "--dev and --update are mutually exclusive" - usage="yes" -fi - -if [ "$dev_mode" = "yes" -a "$quiet" = "yes" ]; then - err_echo "--dev and --quiet are mutually exclusive" - usage="yes" -fi - -if [ "$bisection_search" = "yes" -a "$prebuild_mode" = "yes" ]; then - err_echo "--bisection-search and --prebuild are mutually exclusive" - usage="yes" -fi + run_args += [ + f'--runtime-option "-Djava.library.path={ANDROID_HOST_OUT}/lib64:{ANDROID_HOST_OUT}/nativetest64"' + ] + + if have_image == "no": + if runtime != "art": + error("--no-image is only supported on the art runtime") + sys.exit(1) + run_args += ["--no-image"] + + if create_runner == "yes" and target_mode == "yes": + error("--create-runner does not function for non --host tests") + usage = "yes" + + if dev_mode == "yes" and update_mode == "yes": + error("--dev and --update are mutually exclusive") + usage = "yes" + + if dev_mode == "yes" and quiet == "yes": + error("--dev and --quiet are mutually exclusive") + usage = "yes" + + if bisection_search == "yes" and prebuild_mode == "yes": + error("--bisection-search and --prebuild are mutually exclusive") + usage = "yes" # TODO: Chroot-based bisection search is not supported yet (see below); implement it. -if [ "$bisection_search" = "yes" -a -n "$chroot" ]; then - err_echo "--chroot with --bisection-search is unsupported" - exit 1 -fi - -if [ "$usage" = "no" ]; then - if [ "x$1" = "x" -o "x$1" = "x-" ]; then - test_dir=`basename "$oldwd"` - else - test_dir="$1" - fi - - if [ '!' -d "$test_dir" ]; then - td2=`echo ${test_dir}-*` - if [ '!' -d "$td2" ]; then - err_echo "${test_dir}: no such test directory" - usage="yes" - fi - test_dir="$td2" - fi + if bisection_search == "yes" and chroot: + error("--chroot with --bisection-search is unsupported") + sys.exit(1) + + if usage == "no": + if not arg or arg == "-": + test_dir = os.path.basename(oldwd) + else: + test_dir = arg + + if not os.path.isdir(test_dir): + td2 = glob.glob(f"{test_dir}-*") + if len(td2) == 1 and os.path.isdir(td2[0]): + test_dir = td2[0] + else: + error(f"{test_dir}: no such test directory") + usage = "yes" # Shift to get rid of the test name argument. The rest of the arguments # will get passed to the test run. - shift -fi - -if [ "$usage" = "yes" ]; then - prog=`basename $prog` - ( - echo "usage:" - echo " $prog --help Print this message." - echo " $prog [options] [test-name] Run test normally." - echo " $prog --dev [options] [test-name] Development mode" \ - "(dumps to stdout)." - echo " $prog --create-runner [options] [test-name]" - echo " Creates a runner script for use with other " \ - "tools (e.g. parallel_run.py)." - echo " The script will only run the test portion, and " \ - "share oat and dex files." - echo " $prog --update [options] [test-name] Update mode" \ - "(replaces expected-stdout.txt and expected-stderr.txt)." - echo ' Omitting the test name or specifying "-" will use the' \ - "current directory." - echo " Runtime Options:" - echo " -O Run non-debug rather than debug build (off by default)." - echo " -Xcompiler-option Pass an option to the compiler." - echo " --runtime-option Pass an option to the runtime." - echo " --compact-dex-level Specify a compact dex level to the compiler." - echo " --debug Wait for the default debugger to attach." - echo " --debug-agent <agent-path>" - echo " Wait for the given debugger agent to attach. Currently" - echo " only supported on host." - echo " --debug-wrap-agent use libwrapagentproperties and tools/libjdwp-compat.props" - echo " to load the debugger agent specified by --debug-agent." - echo " --with-agent <agent> Run the test with the given agent loaded with -agentpath:" - echo " --debuggable Whether to compile Java code for a debugger." - echo " --gdb Run under gdb; incompatible with some tests." - echo " --gdb-dex2oat Run dex2oat under the prebuilt lldb." - echo " --gdbserver Start gdbserver (defaults to port :5039)." - echo " --gdbserver-port <port>" - echo " Start gdbserver with the given COMM (see man gdbserver)." - echo " --gdbserver-bin <binary>" - echo " Use the given binary as gdbserver." - echo " --gdb-arg Pass an option to gdb or gdbserver." - echo " --gdb-dex2oat-args Pass options separated by ';' to lldb for dex2oat." - echo " --simpleperf Wraps the dalvikvm invocation in 'simpleperf record ..." - echo " ... simpleperf report' and dumps stats to stdout." - echo " --temp-path [path] Location where to execute the tests." - echo " --interpreter Enable interpreter only mode (off by default)." - echo " --jit Enable jit (off by default)." - echo " --optimizing Enable optimizing compiler (default)." - echo " --no-verify Turn off verification (on by default)." - echo " --verify-soft-fail Force soft fail verification (off by default)." - echo " Verification is enabled if neither --no-verify" - echo " nor --verify-soft-fail is specified." - echo " --no-optimize Turn off optimization (on by default)." - echo " --no-precise Turn off precise GC (on by default)." - echo " --zygote Spawn the process from the Zygote." \ - "If used, then the" - echo " other runtime options are ignored." - echo " --prebuild Run dex2oat on the files before starting test. (default)" - echo " --no-prebuild Do not run dex2oat on the files before starting" - echo " the test." - echo " --strip-dex Strip the dex files before starting test." - echo " --relocate Force the use of relocating in the test, making" - echo " the image and oat files be relocated to a random" - echo " address before running." - echo " --no-relocate Force the use of no relocating in the test. (default)" - echo " --image Run the test using a precompiled boot image. (default)" - echo " --no-image Run the test without a precompiled boot image." - echo " --host Use the host-mode virtual machine." - echo " --invoke-with Pass --invoke-with option to runtime." - echo " --dalvik Use Dalvik (off by default)." - echo " --jvm Use a host-local RI virtual machine." - echo " --use-java-home Use the JAVA_HOME environment variable" - echo " to find the java compiler and runtime" - echo " (if applicable) to run the test with." - echo " --64 Run the test in 64-bit mode" - echo " --bionic Use the (host, 64-bit only) linux_bionic libc runtime" - echo " --runtime-zipapex [file]" - echo " Use the given zipapex file to provide runtime binaries" - echo " --runtime-extracted-zipapex [dir]" - echo " Use the given extracted zipapex directory to provide" - echo " runtime binaries" - echo " --timeout n Test timeout in seconds" - echo " --trace Run with method tracing" - echo " --strace Run with syscall tracing from strace." - echo " --stream Run method tracing in streaming mode (requires --trace)" - echo " --gcstress Run with gc stress testing" - echo " --gcverify Run with gc verification" - echo " --jvmti-trace-stress Run with jvmti method tracing stress testing" - echo " --jvmti-step-stress Run with jvmti single step stress testing" - echo " --jvmti-redefine-stress" - echo " Run with jvmti method redefinition stress testing" - echo " --always-clean Delete the test files even if the test fails." - echo " --never-clean Keep the test files even if the test succeeds." - echo " --chroot [newroot] Run with root directory set to newroot." - echo " --android-root [path] The path on target for the android root. (/system by default)." - echo " --android-i18n-root [path]" - echo " The path on target for the i18n module root." - echo " (/apex/com.android.i18n by default)." - echo " --android-art-root [path]" - echo " The path on target for the ART module root." - echo " (/apex/com.android.art by default)." - echo " --android-tzdata-root [path]" - echo " The path on target for the Android Time Zone Data root." - echo " (/apex/com.android.tzdata by default)." - echo " --dex2oat-swap Use a dex2oat swap file." - echo " --instruction-set-features [string]" - echo " Set instruction-set-features for compilation." - echo " --quiet Don't print anything except failure messages" - echo " --external-log-tags Use ANDROID_LOG_TAGS to set a custom logging level for" - echo " a test run." - echo " --bisection-search Perform bisection bug search." - echo " --vdex Test using vdex as in input to dex2oat. Only works with --prebuild." - echo " --suspend-timeout Change thread suspend timeout ms (default 500000)." - echo " --dex2oat-jobs Number of dex2oat jobs." - ) 1>&2 # Direct to stderr so usage is not printed if --quiet is set. - exit 1 -fi - -cd "$test_dir" -test_dir=`pwd` - -td_info="${test_dir}/${info}" -td_expected_stdout="${test_dir}/${expected_stdout}" -td_expected_stderr="${test_dir}/${expected_stderr}" - -for td_file in "$td_info" "$td_expected_stdout" "$td_expected_stderr"; do - if [ ! -r "$td_file" ]; then - err_echo "${test_dir}: missing file $td_file" - exit 1 - fi -done - -export TEST_NAME=`basename ${test_dir}` - -# Tests named '<number>-checker-*' will also have their CFGs verified with -# Checker when compiled with Optimizing on host. -# Additionally, if the user specifies that the CFG must be dumped, it will -# run the checker for any type of test to generate the CFG. -if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]] || [ "$dump_cfg" = "true" ]; then - if [ "$runtime" = "art" -a "$run_optimizing" = "true" ]; then - # In no-prebuild or no-image mode, the compiler only quickens so disable the checker. - if [ "$prebuild_mode" = "yes" ]; then - run_checker="yes" - - if [ "$target_mode" = "no" ]; then - cfg_output_dir="$tmp_dir" - checker_args="--arch=${host_arch_name^^}" - else - cfg_output_dir="$DEX_LOCATION" - checker_args="--arch=${target_arch_name^^}" - fi - - if [ "$debuggable" = "yes" ]; then - checker_args="$checker_args --debuggable" - fi - - run_args+=(-Xcompiler-option "--dump-cfg=$cfg_output_dir/$cfg_output" -Xcompiler-option -j1) - checker_args="$checker_args --print-cfg" - fi - fi -fi - -run_args+=(--testlib "${testlib}") - -if ! ulimit -f ${file_ulimit}; then - err_echo "ulimit file size setting failed" -fi - -# Extract run-test data from the zip file. -rm -rf "$tmp_dir" -mkdir -p "$tmp_dir/.unzipped" -cd "$tmp_dir" -if [[ "$target_mode" == "yes" ]]; then - zip_file="${ANDROID_HOST_OUT}/etc/art/art-run-test-target-data.zip" - zip_entry="target/${TEST_NAME}" -elif [[ $runtime == "jvm" ]]; then - zip_file="${ANDROID_HOST_OUT}/etc/art/art-run-test-jvm-data.zip" - zip_entry="jvm/${TEST_NAME}" -else - zip_file="${ANDROID_HOST_OUT}/etc/art/art-run-test-host-data.zip" - zip_entry="host/${TEST_NAME}" -fi -unzip -q "${zip_file}" "${zip_entry}/*" -d "$tmp_dir/.unzipped" -mv "$tmp_dir"/.unzipped/${zip_entry}/* "$tmp_dir" - -good="no" -good_run="yes" -export TEST_RUNTIME="${runtime}" -if [ "$dev_mode" = "yes" ]; then - echo "${test_dir}: running..." 1>&2 - "./${run}" "${run_args[@]}" "$@" - run_exit="$?" - - if [ "$run_exit" = "0" ]; then - if [ "$run_checker" = "yes" ]; then - if [ "$target_mode" = "yes" ]; then - adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null - fi - "$checker" $checker_args "$cfg_output" "$tmp_dir" 2>&1 - checker_exit="$?" - if [ "$checker_exit" = "0" ]; then - good="yes" - fi - err_echo "checker exit status: $checker_exit" - else - good="yes" - fi - fi - echo "run exit status: $run_exit" 1>&2 -elif [ "$update_mode" = "yes" ]; then - echo "${test_dir}: running..." 1>&2 - "./${run}" "${run_args[@]}" "$@" >"$test_stdout" 2>"$test_stderr" - if [ "$run_checker" = "yes" ]; then - if [ "$target_mode" = "yes" ]; then - adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null - fi - "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >>"$test_stdout" 2>>"$test_stderr" - fi - sed -e 's/[[:cntrl:]]$//g' <"$test_stdout" >"${td_expected_stdout}" - sed -e 's/[[:cntrl:]]$//g' <"$test_stderr" >"${td_expected_stderr}" - good="yes" -else - echo "${test_dir}: running..." 1>&2 - "./${run}" "${run_args[@]}" "$@" >"$test_stdout" 2>"$test_stderr" - run_exit="$?" - if [ "$run_exit" != "0" ]; then - err_echo "run exit status: $run_exit" - good_run="no" - elif [ "$run_checker" = "yes" ]; then - if [ "$target_mode" = "yes" ]; then - adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null - fi - "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >>"$test_stdout" 2>>"$test_stderr" - checker_exit="$?" - if [ "$checker_exit" != "0" ]; then - err_echo "checker exit status: $checker_exit" - good_run="no" - else - good_run="yes" - fi - else - good_run="yes" - fi - ./$check_cmd "$expected_stdout" "$test_stdout" "$expected_stderr" "$test_stderr" - if [ "$?" = "0" ]; then - if [ "$good_run" = "yes" ]; then - # test_stdout == expected_stdout && test_stderr == expected_stderr - good="yes" - echo "${test_dir}: succeeded!" 1>&2 - fi - fi -fi - -( - if [ "$good" != "yes" -a "$update_mode" != "yes" ]; then - echo "${test_dir}: FAILED!" - echo ' ' - echo '#################### info' - cat "${td_info}" | sed 's/^/# /g' - echo '#################### stdout diffs' - if [ "$run_checker" == "yes" ]; then - # Checker failures dump the whole CFG, so we output the whole diff. - diff --strip-trailing-cr -u "$expected_stdout" "$test_stdout" - else - diff --strip-trailing-cr -u "$expected_stdout" "$test_stdout" | tail -n 10000 - fi - echo '####################' - echo '#################### stderr diffs' - diff --strip-trailing-cr -u "$expected_stderr" "$test_stderr" | tail -n 10000 - echo '####################' - if [ "$strace" = "yes" ]; then - echo '#################### strace output' - tail -n 3000 "$tmp_dir/$strace_output" - echo '####################' - fi - if [ "x$target_mode" = "xno" -a "x$SANITIZE_HOST" = "xaddress" ]; then - # Run the stack script to symbolize any ASAN aborts on the host for SANITIZE_HOST. The - # tools used by the given ABI work for both x86 and x86-64. - echo "ABI: 'x86_64'" | cat - "$test_stdout" "$test_stderr" \ - | $ANDROID_BUILD_TOP/development/scripts/stack | tail -n 3000 - fi - echo ' ' - fi - -) 2>&${real_stderr} 1>&2 - -# Copy the generated CFG to the specified path. -if [ $dump_cfg = "true" ]; then - if [ $run_optimizing != "true" ]; then - err_echo "Can't dump the .cfg if the compiler type isn't set to \"optimizing\"." - else - if [ "$target_mode" = "yes" ]; then - adb pull $chroot/$cfg_output_dir/$cfg_output $dump_cfg_path - else - cp $cfg_output_dir/$cfg_output $dump_cfg_path - fi - fi -fi - -# Attempt bisection only if the test failed. -# TODO: Implement support for chroot-based bisection search. -if [ "$bisection_search" = "yes" -a "$good" != "yes" ]; then - # Bisecting works by skipping different optimization passes which breaks checker assertions. - if [ "$run_checker" == "yes" ]; then - echo "${test_dir}: not bisecting, checker test." 1>&2 - else - # Increase file size limit, bisection search can generate large logfiles. - echo "${test_dir}: bisecting..." 1>&2 - cwd=`pwd` - maybe_device_mode="" - raw_cmd="" - if [ "$target_mode" = "yes" ]; then - # Produce cmdline.sh in $chroot_dex_location. "$@" is passed as a runtime option - # so that cmdline.sh forwards its arguments to dalvikvm. invoke-with is set - # to exec in order to preserve pid when calling dalvikvm. This is required - # for bisection search to correctly retrieve logs from device. - "./${run}" "${run_args[@]}" --runtime-option '"$@"' --invoke-with exec --dry-run "$@" &> /dev/null - adb shell chmod u+x "$chroot_dex_location/cmdline.sh" - maybe_device_mode="--device" - raw_cmd="$DEX_LOCATION/cmdline.sh" - else - raw_cmd="$cwd/${run} --external-log-tags "${run_args[@]}" $@" - fi - # TODO: Pass a `--chroot` option to the bisection_search.py script and use it there. - $ANDROID_BUILD_TOP/art/tools/bisection_search/bisection_search.py \ - $maybe_device_mode \ - --raw-cmd="$raw_cmd" \ - --check-script="$cwd/check" \ - --expected-output="$cwd/expected-stdout.txt" \ - --logfile="$cwd/bisection_log.txt" \ - --timeout=${timeout:-300} - fi -fi - -# Clean up test files. -if [ "$always_clean" = "yes" -o "$good" = "yes" ] && [ "$never_clean" = "no" ]; then - cd "$oldwd" - rm -rf "$tmp_dir" - if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then - adb shell rm -rf $chroot_dex_location - fi - if [ "$good" = "yes" ]; then - exit 0 - fi -fi - - -( - if [ "$always_clean" = "yes" ]; then - echo "${TEST_NAME} files deleted from host " - if [ "$target_mode" == "yes" ]; then - echo "and from target" - fi - else - echo "${TEST_NAME} files left in ${tmp_dir} on host" - if [ "$target_mode" == "yes" ]; then - echo "and in ${chroot_dex_location} on target" - fi - fi - -) 2>&${real_stderr} 1>&2 - -if [ "$never_clean" = "yes" ] && [ "$good" = "yes" ]; then - exit 0 -else - exit 1 -fi + shift() + + if usage == "yes": + prog = os.path.basename(__file__) + # pyformat: disable + help=( + "usage:\n" + f" $prog --help Print this message.\n" + f" $prog [options] [test-name] Run test normally.\n" + f" $prog --dev [options] [test-name] Development mode\n" + "(dumps to stdout).\n" + f" $prog --create-runner [options] [test-name]\n" + " Creates a runner script for use with other \n" + "tools (e.g. parallel_run.py).\n" + " The script will only run the test portion, and \n" + "share oat and dex files.\n" + f" $prog --update [options] [test-name] Update mode\n" + "(replaces expected-stdout.txt and expected-stderr.txt).\n" + ' Omitting the test name or specifying "-" will use the\n' + "current directory.\n" + " Runtime Options:\n" + " -O Run non-debug rather than debug build (off by default).\n" + " -Xcompiler-option Pass an option to the compiler.\n" + " --runtime-option Pass an option to the runtime.\n" + " --compact-dex-level Specify a compact dex level to the compiler.\n" + " --debug Wait for the default debugger to attach.\n" + " --debug-agent <agent-path>\n" + " Wait for the given debugger agent to attach. Currently\n" + " only supported on host.\n" + " --debug-wrap-agent use libwrapagentproperties and tools/libjdwp-compat.props\n" + " to load the debugger agent specified by --debug-agent.\n" + " --with-agent <agent> Run the test with the given agent loaded with -agentpath:\n" + " --debuggable Whether to compile Java code for a debugger.\n" + " --gdb Run under gdb; incompatible with some tests.\n" + " --gdb-dex2oat Run dex2oat under the prebuilt lldb.\n" + " --gdbserver Start gdbserver (defaults to port :5039).\n" + " --gdbserver-port <port>\n" + " Start gdbserver with the given COMM (see man gdbserver).\n" + " --gdbserver-bin <binary>\n" + " Use the given binary as gdbserver.\n" + " --gdb-arg Pass an option to gdb or gdbserver.\n" + " --gdb-dex2oat-args Pass options separated by ';' to lldb for dex2oat.\n" + " --simpleperf Wraps the dalvikvm invocation in 'simpleperf record ...\n" + " ... simpleperf report' and dumps stats to stdout.\n" + " --temp-path [path] Location where to execute the tests.\n" + " --interpreter Enable interpreter only mode (off by default).\n" + " --jit Enable jit (off by default).\n" + " --optimizing Enable optimizing compiler (default).\n" + " --no-verify Turn off verification (on by default).\n" + " --verify-soft-fail Force soft fail verification (off by default).\n" + " Verification is enabled if neither --no-verify\n" + " nor --verify-soft-fail is specified.\n" + " --no-optimize Turn off optimization (on by default).\n" + " --no-precise Turn off precise GC (on by default).\n" + " --zygote Spawn the process from the Zygote.\n" + "If used, then the\n" + " other runtime options are ignored.\n" + " --prebuild Run dex2oat on the files before starting test. (default)\n" + " --no-prebuild Do not run dex2oat on the files before starting\n" + " the test.\n" + " --strip-dex Strip the dex files before starting test.\n" + " --relocate Force the use of relocating in the test, making\n" + " the image and oat files be relocated to a random\n" + " address before running.\n" + " --no-relocate Force the use of no relocating in the test. (default)\n" + " --image Run the test using a precompiled boot image. (default)\n" + " --no-image Run the test without a precompiled boot image.\n" + " --host Use the host-mode virtual machine.\n" + " --invoke-with Pass --invoke-with option to runtime.\n" + " --dalvik Use Dalvik (off by default).\n" + " --jvm Use a host-local RI virtual machine.\n" + " --use-java-home Use the JAVA_HOME environment variable\n" + " to find the java compiler and runtime\n" + " (if applicable) to run the test with.\n" + " --64 Run the test in 64-bit mode\n" + " --bionic Use the (host, 64-bit only) linux_bionic libc runtime\n" + " --runtime-zipapex [file]\n" + " Use the given zipapex file to provide runtime binaries\n" + " --runtime-extracted-zipapex [dir]\n" + " Use the given extracted zipapex directory to provide\n" + " runtime binaries\n" + " --timeout n Test timeout in seconds\n" + " --trace Run with method tracing\n" + " --strace Run with syscall tracing from strace.\n" + " --stream Run method tracing in streaming mode (requires --trace)\n" + " --gcstress Run with gc stress testing\n" + " --gcverify Run with gc verification\n" + " --jvmti-trace-stress Run with jvmti method tracing stress testing\n" + " --jvmti-step-stress Run with jvmti single step stress testing\n" + " --jvmti-redefine-stress\n" + " Run with jvmti method redefinition stress testing\n" + " --always-clean Delete the test files even if the test fails.\n" + " --never-clean Keep the test files even if the test succeeds.\n" + " --chroot [newroot] Run with root directory set to newroot.\n" + " --android-root [path] The path on target for the android root. (/system by default).\n" + " --android-i18n-root [path]\n" + " The path on target for the i18n module root.\n" + " (/apex/com.android.i18n by default).\n" + " --android-art-root [path]\n" + " The path on target for the ART module root.\n" + " (/apex/com.android.art by default).\n" + " --android-tzdata-root [path]\n" + " The path on target for the Android Time Zone Data root.\n" + " (/apex/com.android.tzdata by default).\n" + " --dex2oat-swap Use a dex2oat swap file.\n" + " --instruction-set-features [string]\n" + " Set instruction-set-features for compilation.\n" + " --quiet Don't print anything except failure messages\n" + " --external-log-tags Use ANDROID_LOG_TAGS to set a custom logging level for\n" + " a test run.\n" + " --bisection-search Perform bisection bug search.\n" + " --vdex Test using vdex as in input to dex2oat. Only works with --prebuild.\n" + " --suspend-timeout Change thread suspend timeout ms (default 500000).\n" + " --dex2oat-jobs Number of dex2oat jobs.\n" + ) + # pyformat: enable + error(help) + sys.exit(1) + + os.chdir(test_dir) + test_dir = os.getcwd() + + TEST_NAME = os.path.basename(test_dir) + export("TEST_NAME", TEST_NAME) + + # Tests named '<number>-checker-*' will also have their CFGs verified with + # Checker when compiled with Optimizing on host. + # Additionally, if the user specifies that the CFG must be dumped, it will + # run the checker for any type of test to generate the CFG. + if re.match("[0-9]+-checker-", TEST_NAME) or dump_cfg == "true": + if runtime == "art" and run_optimizing == "true": + # In no-prebuild or no-image mode, the compiler only quickens so disable the checker. + if prebuild_mode == "yes": + run_checker = "yes" + + if target_mode == "no": + cfg_output_dir = tmp_dir + checker_args = f"--arch={host_arch_name.upper()}" + else: + cfg_output_dir = DEX_LOCATION + checker_args = f"--arch={target_arch_name.upper()}" + + if debuggable == "yes": + checker_args += " --debuggable" + + run_args += [ + f'-Xcompiler-option "--dump-cfg={cfg_output_dir}/{cfg_output}" -Xcompiler-option -j1' + ] + checker_args = f"{checker_args} --print-cfg" + + run_args += [f'--testlib "{testlib}"'] + + resource.setrlimit(resource.RLIMIT_FSIZE, (file_ulimit * 1024, resource.RLIM_INFINITY)) + + # Extract run-test data from the zip file. + shutil.rmtree(tmp_dir) + os.makedirs(f"{tmp_dir}/.unzipped") + os.chdir(tmp_dir) + m = re.match("[0-9]*([0-9][0-9])-.*", TEST_NAME) + assert m, "Can not find test number in " + TEST_NAME + SHARD = "HiddenApi" if "hiddenapi" in TEST_NAME else m.group(1) + if target_mode == "yes": + zip_file = f"{ANDROID_HOST_OUT}/etc/art/art-run-test-target-data-shard{SHARD}.zip" + zip_entry = f"target/{TEST_NAME}/" + elif runtime == "jvm": + zip_file = f"{ANDROID_HOST_OUT}/etc/art/art-run-test-jvm-data-shard{SHARD}.zip" + zip_entry = f"jvm/{TEST_NAME}/" + else: + zip_file = f"{ANDROID_HOST_OUT}/etc/art/art-run-test-host-data-shard{SHARD}.zip" + zip_entry = f"host/{TEST_NAME}/" + zip = ZipFile(zip_file, "r") + zip_entries = [e for e in zip.namelist() if e.startswith(zip_entry)] + zip.extractall(Path(tmp_dir) / ".unzipped", members=zip_entries) + for entry in (Path(tmp_dir) / ".unzipped" / zip_entry).iterdir(): + entry.rename(Path(tmp_dir) / entry.name) + + def clean_up(passed: bool): + if always_clean == "yes" or (passed and never_clean == "no"): + os.chdir(oldwd) + shutil.rmtree(tmp_dir) + if target_mode == "yes": + if ON_VM: + run(f"{SSH_CMD} \"rm -rf {chroot_dex_location}\"") + else: + run(f"adb shell rm -rf {chroot_dex_location}") + print(f"{TEST_NAME} files deleted from host" + + (" and from target" if target_mode == "yes" else "")) + else: + print(f"{TEST_NAME} files left in {tmp_dir} on host" + + (f" and in {chroot_dex_location} on target" if target_mode == "yes" else "")) + atexit.unregister(clean_up) + # TODO: Run this in global try-finally once the script is more refactored. + atexit.register(clean_up, passed=False) + + ctx = RunTestContext(Path(tmp_dir), target_mode == "yes", chroot, DEX_LOCATION, TEST_NAME) + td_info = f"{test_dir}/{info}" + for td_file in [td_info, ctx.expected_stdout, ctx.expected_stderr]: + assert os.access(td_file, os.R_OK) + + joined_run_args = " ".join(run_args) + joined_args = " ".join(args) + + # Create runner (bash script that executes the whole test) + def create_runner_script() -> Path: + parsed_args = default_run_module.parse_args(shlex.split(" ".join(run_args + args))) + parsed_args.stdout_file = os.path.join(DEX_LOCATION, test_stdout) + parsed_args.stderr_file = os.path.join(DEX_LOCATION, test_stderr) + + ctx.run(f"cd {DEX_LOCATION}") + if target_mode != "yes": + # Make "out" directory accessible from test directory. + ctx.run(f"ln -s -f -t {DEX_LOCATION} {ANDROID_BUILD_TOP}/out") + # Clear the stdout/stderr files (create empty files). + ctx.run(f"echo -n > {test_stdout} && echo -n > {test_stderr}") + + script = Path(tmp_dir) / "run.py" + if script.exists(): + module = SourceFileLoader("run_" + TEST_NAME, str(script)).load_module() + module.run(ctx, parsed_args) + else: + default_run_module.default_run(ctx, parsed_args) + + runner = Path(tmp_dir) / "run.sh" + runner.write_text("\n".join(ctx.runner)) + runner.chmod(0o777) + return runner + + # Test might not execute anything but we still expect the output files to exist. + Path(test_stdout).touch() + Path(test_stderr).touch() + + export("TEST_RUNTIME", runtime) + + print(f"{test_dir}: Create runner script...") + runner = create_runner_script() + + print(f"{test_dir}: Run...") + if target_mode == "yes": + # Prepare the on-device test directory + if ON_VM: + run(f"{SSH_CMD} 'rm -rf {chroot_dex_location} && mkdir -p {chroot_dex_location}'") + else: + run("adb root") + run("adb wait-for-device") + run(f"adb shell 'rm -rf {chroot_dex_location} && mkdir -p {chroot_dex_location}'") + push_files = [Path(runner.name)] + push_files += list(Path(".").glob(f"{TEST_NAME}*.jar")) + push_files += list(Path(".").glob(f"expected-*.txt")) + push_files += [p for p in [Path("profile"), Path("res")] if p.exists()] + push_files = " ".join(map(str, push_files)) + if ON_VM: + run(f"{SCP_CMD} {push_files} {SSH_USER}@{SSH_HOST}:{chroot_dex_location}") + else: + run("adb push {} {}".format(push_files, chroot_dex_location)) + + if ON_VM: + run(f"{SSH_CMD} {CHROOT_CMD} bash {DEX_LOCATION}/run.sh", + fail_message=f"Runner {chroot_dex_location}/run.sh failed") + else: + chroot_prefix = f"chroot {chroot}" if chroot else "" + run(f"adb shell {chroot_prefix} sh {DEX_LOCATION}/run.sh", + fail_message=f"Runner {chroot_dex_location}/run.sh failed") + + # Copy the on-device stdout/stderr to host. + pull_files = [test_stdout, test_stderr, "expected-stdout.txt", "expected-stderr.txt"] + if ON_VM: + srcs = " ".join(f"{SSH_USER}@{SSH_HOST}:{chroot_dex_location}/{f}" for f in pull_files) + run(f"{SCP_CMD} {srcs} .") + else: + run("adb pull {} .".format(" ".join(f"{chroot_dex_location}/{f}" for f in pull_files))) + else: + run(str(runner), fail_message=f"Runner {str(runner)} failed") + + # NB: There is no exit code or return value. + # Failing tests just raise python exception. + os.chdir(tmp_dir) + if update_mode == "yes": + for src, dst in [(test_stdout, os.path.join(test_dir, ctx.expected_stdout.name)), + (test_stderr, os.path.join(test_dir, ctx.expected_stderr.name))]: + if "[DO_NOT_UPDATE]" not in open(dst).readline(): + copyfile(src, dst) + + print("#################### info") + run(f'cat "{td_info}" | sed "s/^/# /g"') + print("#################### stdout diff") + proc_out = run(f'diff --strip-trailing-cr -u ' + f'"{ctx.expected_stdout}" "{test_stdout}"', check=False) + print("#################### stderr diff") + proc_err = run(f'diff --strip-trailing-cr -u ' + f'"{ctx.expected_stderr}" "{test_stderr}"', check=False) + if strace == "yes": + print("#################### strace output (trimmed to 3000 lines)") + # Some tests do not run dalvikvm, in which case the trace does not exist. + run(f'tail -n 3000 "{tmp_dir}/{strace_output}"', check=False) + SANITIZE_HOST = os.environ.get("SANITIZE_HOST") + if target_mode == "no" and SANITIZE_HOST == "address": + # Run the stack script to symbolize any ASAN aborts on the host for SANITIZE_HOST. The + # tools used by the given ABI work for both x86 and x86-64. + print("#################### symbolizer (trimmed to 3000 lines)") + run(f'''echo "ABI: 'x86_64'" | cat - "{test_stdout}" "{test_stderr}"''' + f"""| {ANDROID_BUILD_TOP}/development/scripts/stack | tail -n 3000""") + print("####################", flush=True) + if proc_out.returncode != 0 or proc_err.returncode != 0: + kind = ((["stdout"] if proc_out.returncode != 0 else []) + + (["stderr"] if proc_err.returncode != 0 else [])) + fail("{} did not match the expected file".format(" and ".join(kind))) + + if run_checker == "yes": + if target_mode == "yes": + if ON_VM: + run(f'{SCP_CMD} "{SSH_USER}@${SSH_HOST}:{CHROOT}/{cfg_output_dir}/{cfg_output}"') + else: + run(f'adb pull "{chroot}/{cfg_output_dir}/{cfg_output}"') + run(f'"{checker}" -q {checker_args} "{cfg_output}" "{tmp_dir}"', + fail_message="CFG checker failed") + + # Copy the generated CFG to the specified path. + if dump_cfg == "true": + assert run_optimizing == "true", "The CFG can be dumped only in optimizing mode" + if target_mode == "yes": + if ON_VM: + run(f'{SCP_CMD} "{SSH_USER}@${SSH_HOST}:{CHROOT}/{cfg_output_dir}/{cfg_output} {dump_cfg_output}"') + else: + run(f"adb pull {chroot}/{cfg_output_dir}/{cfg_output} {dump_cfg_path}") + else: + run(f"cp {cfg_output_dir}/{cfg_output} {dump_cfg_path}") + + clean_up(passed=True) + print(f"{COLOR_GREEN}{test_dir}: PASSED{COLOR_NORMAL}") |