summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/Android.run-test.bp21
-rwxr-xr-xtest/Android.run-test.bp.py7
-rwxr-xr-xtest/default_run.py21
-rw-r--r--test/globals.py24
-rwxr-xr-xtest/run-test33
-rwxr-xr-xtest/run_test_build.py102
6 files changed, 138 insertions, 70 deletions
diff --git a/test/Android.run-test.bp b/test/Android.run-test.bp
index a7b4ae6929..f119ec75b4 100644
--- a/test/Android.run-test.bp
+++ b/test/Android.run-test.bp
@@ -2639,16 +2639,13 @@ prebuilt_etc_host {
genrule_defaults {
name: "art-run-test-host-data-defaults",
- tool_files: [
- "run_test_build.py",
- ":art-run-test-bootclasspath",
- ],
srcs: [
// Since genrules are sandboxed, all the sources they use must be listed in
// the Android.bp file. Some tests have symlinks to files from other tests, and
// those must also be listed to avoid a dangling symlink in the sandbox.
"jvmti-common/*.java",
"utils/python/**/*.py",
+ ":art-run-test-bootclasspath",
":development_docs",
":asm-9.6-filegroup",
":ojluni-AbstractCollection",
@@ -2663,7 +2660,9 @@ genrule_defaults {
"testrunner/*.py",
"knownfailures.json",
"default_run.py",
+ "globals.py",
"run-test",
+ "run_test_build.py",
],
tools: [
"android-smali",
@@ -5760,16 +5759,13 @@ prebuilt_etc_host {
genrule_defaults {
name: "art-run-test-target-data-defaults",
- tool_files: [
- "run_test_build.py",
- ":art-run-test-bootclasspath",
- ],
srcs: [
// Since genrules are sandboxed, all the sources they use must be listed in
// the Android.bp file. Some tests have symlinks to files from other tests, and
// those must also be listed to avoid a dangling symlink in the sandbox.
"jvmti-common/*.java",
"utils/python/**/*.py",
+ ":art-run-test-bootclasspath",
":development_docs",
":asm-9.6-filegroup",
":ojluni-AbstractCollection",
@@ -5784,7 +5780,9 @@ genrule_defaults {
"testrunner/*.py",
"knownfailures.json",
"default_run.py",
+ "globals.py",
"run-test",
+ "run_test_build.py",
],
tools: [
"android-smali",
@@ -8881,16 +8879,13 @@ prebuilt_etc_host {
genrule_defaults {
name: "art-run-test-jvm-data-defaults",
- tool_files: [
- "run_test_build.py",
- ":art-run-test-bootclasspath",
- ],
srcs: [
// Since genrules are sandboxed, all the sources they use must be listed in
// the Android.bp file. Some tests have symlinks to files from other tests, and
// those must also be listed to avoid a dangling symlink in the sandbox.
"jvmti-common/*.java",
"utils/python/**/*.py",
+ ":art-run-test-bootclasspath",
":development_docs",
":asm-9.6-filegroup",
":ojluni-AbstractCollection",
@@ -8905,7 +8900,9 @@ genrule_defaults {
"testrunner/*.py",
"knownfailures.json",
"default_run.py",
+ "globals.py",
"run-test",
+ "run_test_build.py",
],
tools: [
"android-smali",
diff --git a/test/Android.run-test.bp.py b/test/Android.run-test.bp.py
index d7934661b3..e208672b11 100755
--- a/test/Android.run-test.bp.py
+++ b/test/Android.run-test.bp.py
@@ -111,16 +111,13 @@ def main():
f.write(textwrap.dedent(f"""
genrule_defaults {{
name: "art-run-test-{mode}-data-defaults",
- tool_files: [
- "run_test_build.py",
- ":art-run-test-bootclasspath",
- ],
srcs: [
// Since genrules are sandboxed, all the sources they use must be listed in
// the Android.bp file. Some tests have symlinks to files from other tests, and
// those must also be listed to avoid a dangling symlink in the sandbox.
"jvmti-common/*.java",
"utils/python/**/*.py",
+ ":art-run-test-bootclasspath",
":development_docs",
":asm-9.6-filegroup",
":ojluni-AbstractCollection",
@@ -135,7 +132,9 @@ def main():
"testrunner/*.py",
"knownfailures.json",
"default_run.py",
+ "globals.py",
"run-test",
+ "run_test_build.py",
],
tools: [
"android-smali",
diff --git a/test/default_run.py b/test/default_run.py
index c5e9d376ae..9d7179e68a 100755
--- a/test/default_run.py
+++ b/test/default_run.py
@@ -15,6 +15,7 @@
import sys, os, shutil, shlex, re, subprocess, glob
from argparse import ArgumentParser, BooleanOptionalAction, Namespace
+from globals import BOOTCLASSPATH
from os import path
from os.path import isfile, isdir, basename
from subprocess import check_output, DEVNULL, PIPE, STDOUT
@@ -144,29 +145,11 @@ def get_target_arch(is64: bool) -> str:
assert len(arches) == 1, f"Can not find (unique) 32-bit arch in {arches}"
return arches[0]
-# Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
-# because that's what we use for compiling the boot.art image.
-# It may contain additional modules from TEST_CORE_JARS.
-bpath_modules = ("core-oj core-libart okhttp bouncycastle apache-xml core-icu4j"
- " conscrypt")
-
# Helper function to construct paths for apex modules (for both -Xbootclasspath and
# -Xbootclasspath-location).
def get_apex_bootclasspath_impl(bpath_prefix: str):
- bpath_separator = ""
- bpath = ""
- bpath_jar = ""
- for bpath_module in bpath_modules.split(" "):
- apex_module = "com.android.art"
- if bpath_module == "conscrypt":
- apex_module = "com.android.conscrypt"
- if bpath_module == "core-icu4j":
- apex_module = "com.android.i18n"
- bpath_jar = f"/apex/{apex_module}/javalib/{bpath_module}.jar"
- bpath += f"{bpath_separator}{bpath_prefix}{bpath_jar}"
- bpath_separator = ":"
- return bpath
+ return ":".join(bpath_prefix + bpath for bpath in BOOTCLASSPATH)
# Gets a -Xbootclasspath paths with the apex modules.
diff --git a/test/globals.py b/test/globals.py
new file mode 100644
index 0000000000..fa51150776
--- /dev/null
+++ b/test/globals.py
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BOOTCLASSPATH = [
+ "/apex/com.android.art/javalib/core-oj.jar",
+ "/apex/com.android.art/javalib/core-libart.jar",
+ "/apex/com.android.art/javalib/okhttp.jar",
+ "/apex/com.android.art/javalib/bouncycastle.jar",
+ "/apex/com.android.art/javalib/apache-xml.jar",
+ "/apex/com.android.i18n/javalib/core-icu4j.jar",
+ "/apex/com.android.conscrypt/javalib/conscrypt.jar",
+] \ No newline at end of file
diff --git a/test/run-test b/test/run-test
index 5af84c89ca..cc31077818 100755
--- a/test/run-test
+++ b/test/run-test
@@ -105,11 +105,12 @@ class RunTestContext:
# Make unique temporary directory guarded by lock file.
# The name is deterministic (appending suffix as needed).
def make_tmp_dir():
- parent = Path(os.environ.get("TMPDIR", "/tmp/art/rtest"))
+ parent = Path(os.environ.get("TMPDIR", "/tmp")) / "art" / "test"
parent.mkdir(parents=True, exist_ok=True)
- args_hash = sha1((" ".join(sys.argv[1:])).encode()).digest().hex()
+ args = [a for a in sys.argv[1:] if not a.startswith("--create-runner")]
+ hash = sha1((" ".join(args)).encode()).hexdigest()
for i in range(100):
- tmp_dir = parent / (f"{args_hash[:8]}" + (f"-{i}" if i > 0 else ""))
+ tmp_dir = parent / (f"{hash[:8]}" + (f"-{i}" if i > 0 else ""))
lock = tmp_dir.with_suffix(".lock") # NB: Next to the directory, not inside.
lock_handle = open(lock, "w")
try:
@@ -177,7 +178,10 @@ if True:
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}")
+ if env.ART_TEST_RUN_FROM_SOONG:
+ export("DEX_LOCATION", f"/data/local/tmp/art/test/{test_dir}")
+ else:
+ 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.
@@ -689,7 +693,10 @@ if True:
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 env.ART_TEST_RUN_FROM_SOONG:
+ run_args += ['--boot "/data/local/tmp/art/apex/art_boot_images/boot.art"']
+ else:
+ run_args += ['--boot "/system/framework/art_boot_images/boot.art"']
if relocate:
run_args += ["--relocate"]
else:
@@ -773,15 +780,22 @@ if True:
# Extract run-test data from the zip file.
def unzip():
- shutil.rmtree(tmp_dir)
if env.ART_TEST_RUN_FROM_SOONG:
# We already have the unzipped copy of the data.
assert target_mode
src = Path(ANDROID_BUILD_TOP) / "out" / "zip" / "target" / TEST_NAME
assert src.exists(), src
+ shutil.rmtree(tmp_dir)
copytree(src, tmp_dir)
os.chdir(tmp_dir)
return
+
+ # Clear the contents, but keep the directory just in case it is open in terminal.
+ for file in Path(tmp_dir).iterdir():
+ if file.is_file() or file.is_symlink():
+ file.unlink()
+ else:
+ shutil.rmtree(file)
os.makedirs(f"{tmp_dir}/.unzipped")
os.chdir(tmp_dir)
m = re.match("[0-9]*([0-9][0-9])-.*", TEST_NAME)
@@ -809,12 +823,12 @@ if True:
if always_clean or (passed and not never_clean):
os.chdir(oldwd)
shutil.rmtree(tmp_dir)
- os.remove(tmp_dir_lock)
if target_mode:
if ON_VM:
run(f"{SSH_CMD} \"rm -rf {chroot_dex_location}\"")
else:
run(f"adb shell rm -rf {chroot_dex_location}")
+ os.remove(tmp_dir_lock)
print(f"{TEST_NAME} files deleted from host" +
(" and from target" if target_mode else ""))
else:
@@ -874,10 +888,9 @@ if True:
if args.create_runner:
# TODO: Generate better unique names.
- name = [a for a in sys.argv[1:] if not a.startswith("--create-runner")]
- hash = sha1((" ".join(name)).encode()).digest().hex()[:8]
- dst = args.create_runner / f"{TEST_NAME}-{hash}"
+ dst = args.create_runner / TEST_NAME / f"{Path(tmp_dir).name}.sh"
assert not dst.exists(), dst
+ dst.parent.mkdir(parents=True, exist_ok=True)
copyfile(runner, dst)
# Script debugging feature - just export the runner script into a directory,
diff --git a/test/run_test_build.py b/test/run_test_build.py
index 1d64897436..a93950f02f 100755
--- a/test/run_test_build.py
+++ b/test/run_test_build.py
@@ -42,6 +42,8 @@ from tempfile import TemporaryDirectory, NamedTemporaryFile
from typing import Dict, List, Union, Set, Optional
from multiprocessing import cpu_count
+from globals import BOOTCLASSPATH
+
USE_RBE = 100 # Percentage of tests that can use RBE (between 0 and 100)
lock_file = None # Keep alive as long as this process is alive.
@@ -510,31 +512,83 @@ class BuildTestContext:
else:
zip(Path(self.test_name + ".jar"), Path("classes.dex"))
+# Create bash script that compiles the boot image on device.
+# This is currently only used for eng-prod testing (which is different
+# to the local and LUCI code paths that use buildbot-sync.sh script).
+def create_setup_script(is64: bool):
+ out = "/data/local/tmp/art/apex/art_boot_images"
+ isa = 'arm64' if is64 else 'arm'
+ jar = BOOTCLASSPATH
+ cmd = [
+ f"/apex/com.android.art/bin/{'dex2oat64' if is64 else 'dex2oat32'}",
+ "--runtime-arg", f"-Xbootclasspath:{':'.join(jar)}",
+ "--runtime-arg", f"-Xbootclasspath-locations:{':'.join(jar)}",
+ ] + [f"--dex-file={j}" for j in jar] + [f"--dex-location={j}" for j in jar] + [
+ f"--instruction-set={isa}",
+ "--base=0x70000000",
+ "--compiler-filter=speed-profile",
+ "--profile-file=/apex/com.android.art/etc/boot-image.prof",
+ "--avoid-storing-invocation",
+ "--generate-debug-info",
+ "--generate-build-id",
+ "--image-format=lz4hc",
+ "--strip",
+ "--android-root=out/empty",
+ f"--image={out}/{isa}/boot.art",
+ f"--oat-file={out}/{isa}/boot.oat",
+ ]
+ return [
+ f"rm -rf {out}/{isa}",
+ f"mkdir -p {out}/{isa}",
+ " ".join(cmd),
+ ]
+
# Create bash scripts that can fully execute the run tests.
# This can be used in CI to execute the tests without running `testrunner.py`.
# This takes into account any custom behaviour defined in per-test `run.py`.
# We generate distinct scripts for all of the pre-defined variants.
-def create_ci_runner_scripts(mode, test_names):
- with TemporaryDirectory() as tmpdir:
- python = sys.executable
- script = 'art/test/testrunner/testrunner.py'
- envs = {
- "ANDROID_BUILD_TOP": str(Path(getcwd()).absolute()),
- "ART_TEST_RUN_FROM_SOONG": "true",
- # TODO: Make the runner scripts target agnostic.
- # The only dependency is setting of "-Djava.library.path".
- "TARGET_ARCH": "arm64",
- "TARGET_2ND_ARCH": "arm",
- "TMPDIR": Path(getcwd()) / "tmp",
+def create_ci_runner_scripts(out, mode, test_names):
+ out.mkdir(parents=True)
+ setup = out / "setup.sh"
+ setup_script = create_setup_script(False) + create_setup_script(True)
+ setup.write_text("\n".join(setup_script))
+
+ python = sys.executable
+ script = 'art/test/testrunner/testrunner.py'
+ envs = {
+ "ANDROID_BUILD_TOP": str(Path(getcwd()).absolute()),
+ "ART_TEST_RUN_FROM_SOONG": "true",
+ # TODO: Make the runner scripts target agnostic.
+ # The only dependency is setting of "-Djava.library.path".
+ "TARGET_ARCH": "arm64",
+ "TARGET_2ND_ARCH": "arm",
+ "TMPDIR": Path(getcwd()) / "tmp",
+ }
+ args = [
+ f"--run-test-option=--create-runner={out}",
+ f"-j={cpu_count()}",
+ f"--{mode}",
+ ]
+ run([python, script] + args + test_names, env=envs, check=True)
+ tests = {
+ "setup": {
+ "adb push": [[str(setup.relative_to(out)), "/data/local/tmp/art/setup.sh"]],
+ "adb shell": [["sh", "/data/local/tmp/art/setup.sh"]],
+ },
+ }
+ for runner in Path(out).glob("*/*.sh"):
+ test_name = runner.parent.name
+ test_hash = runner.stem
+ target_dir = f"/data/local/tmp/art/test/{test_hash}"
+ tests[f"{test_name}-{test_hash}"] = {
+ "dependencies": ["setup"],
+ "adb push": [
+ [f"../{mode}/{test_name}/", f"{target_dir}/"],
+ [str(runner.relative_to(out)), f"{target_dir}/run.sh"]
+ ],
+ "adb shell": [["sh", f"{target_dir}/run.sh"]],
}
- args = [
- f"--run-test-option=--create-runner={tmpdir}",
- f"-j={cpu_count()}",
- f"--{mode}",
- ]
- run([python, script] + args + test_names, env=envs, check=True)
- runners = {r.name: r.read_text().split("\n") for r in Path(tmpdir).glob("*")}
- return [{"name": name, "runner": bash} for name, bash in runners.items()]
+ return tests
# If we build just individual shard, we want to split the work among all the cores,
# but if the build system builds all shards, we don't want to overload the machine.
@@ -603,11 +657,9 @@ def main() -> None:
if args.mode == "target":
os.chdir(android_build_top)
test_names = [ctx.test_name for ctx in tests]
- data = create_ci_runner_scripts(args.mode, test_names)
- dst = ziproot / "runner" / args.out.with_suffix(".json").name
- dst.parent.mkdir(parents=True)
- text = json.dumps(data, ensure_ascii=False, indent=2)
- Path(dst).write_text(text)
+ dst = ziproot / "runner" / args.out.with_suffix(".tests.json").name
+ tests = create_ci_runner_scripts(dst.parent, args.mode, test_names)
+ dst.write_text(json.dumps(tests, indent=2, sort_keys=True))
# Create the final zip file which contains the content of the temporary directory.
soong_zip = android_build_top / args.soong_zip