Refactor individual run-test build scripts

Follow the same convention as run-test run scripts.

The python files shall export build function,
rather than doing the work when the script is loaded.

This has the advantage that we now pass context/arguments
to the function (rather than using environment variables).

Test: the generated build artefacts are identical
Change-Id: I90e0ef0d2e31b27813042d51d07b5ae132e1e704
diff --git a/test/000-nop/build.py b/test/000-nop/build.py
index 846e9a6..54f21cc 100644
--- a/test/000-nop/build.py
+++ b/test/000-nop/build.py
@@ -13,4 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Nothing to do here.
+
+def build(ctx):
+  pass  # Nothing to do here.
diff --git a/test/004-JniTest/build.py b/test/004-JniTest/build.py
index e31d770..26745ab 100644
--- a/test/004-JniTest/build.py
+++ b/test/004-JniTest/build.py
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import shutil, os
 
 #
@@ -27,11 +26,13 @@
 # has a different ABI and cannot be tested on RI.
 #
 
-# Use release mode to check optimizations do not break JNI.
-build_run_test(d8_flags=['--release'])
 
-# Remove the *-aotex build artifacts (but keep src-aotex) with dalvik.* annotations.
-shutil.rmtree("classes-aotex")
-if os.environ["BUILD_MODE"] != "jvm":
-  os.remove("classes-aotex.jar")
-  os.remove("004-JniTest-aotex.jar")
+# Use release mode to check optimizations do not break JNI.
+def build(ctx):
+  ctx.default_build(d8_flags=["--release"])
+
+  # Remove the *-aotex build artifacts (but keep src-aotex) with dalvik.* annotations.
+  shutil.rmtree("classes-aotex")
+  if os.environ["BUILD_MODE"] != "jvm":
+    os.remove("classes-aotex.jar")
+    os.remove("004-JniTest-aotex.jar")
diff --git a/test/005-annotations/build.py b/test/005-annotations/build.py
index 8cf988c..a3aefce 100644
--- a/test/005-annotations/build.py
+++ b/test/005-annotations/build.py
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Build intermediate object to preserve class-retention annotations.
-build_run_test(d8_flags=['--intermediate'])
+def build(ctx):
+  ctx.default_build(d8_flags=['--intermediate'])
diff --git a/test/065-mismatched-implements/build.py b/test/065-mismatched-implements/build.py
index 4284d83..bc346b0 100644
--- a/test/065-mismatched-implements/build.py
+++ b/test/065-mismatched-implements/build.py
@@ -13,11 +13,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Don't use desugar because the build fails when it encounters ICCE.
 #
 # Exception in thread "main" java.lang.IllegalArgumentException
 #  at com.google.common.base.Preconditions.checkArgument(Preconditions.java:108)
 #  at com.google.devtools.build.android.desugar.DefaultMethodClassFixer$DefaultMethodFinder.visit(DefaultMethodClassFixer.java:295)
-build_run_test(use_desugar=False)
+def build(ctx):
+  ctx.default_build(use_desugar=False)
diff --git a/test/066-mismatched-super/build.py b/test/066-mismatched-super/build.py
index 337bd29..59b119d 100644
--- a/test/066-mismatched-super/build.py
+++ b/test/066-mismatched-super/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_desugar=False)
+def build(ctx):
+  ctx.default_build(use_desugar=False)
diff --git a/test/071-dexfile-map-clean/build.py b/test/071-dexfile-map-clean/build.py
index f8c3efd..ab9c4c3 100644
--- a/test/071-dexfile-map-clean/build.py
+++ b/test/071-dexfile-map-clean/build.py
@@ -13,10 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Any JAR files used by this test shall have their classes.dex be stored, NOT compressed.
 # This is needed for our test correctness which validates classes.dex are mapped file-backed.
 #
 # In addition, align to at least 4 bytes since that's the dex alignment requirement.
-build_run_test(zip_compression_method="store", zip_align_bytes="4")
+def build(ctx):
+  ctx.default_build(zip_compression_method="store", zip_align_bytes="4")
diff --git a/test/089-many-methods/build.py b/test/089-many-methods/build.py
index 052ae72..c862ef8 100644
--- a/test/089-many-methods/build.py
+++ b/test/089-many-methods/build.py
@@ -13,14 +13,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-# Specify old API level as d8 automagically produces a multidex file
-# when the API level is above 20. Failing the build here is deliberate.
-# Force DEX generation so test also passes with --jvm.
-try:
-  build_run_test(api_level=20, need_dex=True)
-  assert False, "Test was not expected to build successfully"
-except Exception as e:
-  # Check that a build failure happened (the test is not expected to run).
-  assert "Cannot fit requested classes in a single dex" in str(e), e
+def build(ctx):
+  # Specify old API level as d8 automagically produces a multidex file
+  # when the API level is above 20. Failing the build here is deliberate.
+  # Force DEX generation so test also passes with --jvm.
+  try:
+    ctx.default_build(api_level=20, need_dex=True)
+    assert False, "Test was not expected to build successfully"
+  except Exception as e:
+    # Check that a build failure happened (the test is not expected to run).
+    assert "Cannot fit requested classes in a single dex" in str(e), e
diff --git a/test/160-read-barrier-stress/build.py b/test/160-read-barrier-stress/build.py
index d6b35b1..107499c 100644
--- a/test/160-read-barrier-stress/build.py
+++ b/test/160-read-barrier-stress/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/166-bad-interface-super/build.py b/test/166-bad-interface-super/build.py
index f74f0e9..e4502b3 100644
--- a/test/166-bad-interface-super/build.py
+++ b/test/166-bad-interface-super/build.py
@@ -13,11 +13,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import os
 
-# Use the jasmin sources for JVM, otherwise the smali sources.
-if os.environ["BUILD_MODE"] == "jvm":
-  build_run_test(has_smali=False)
-else:
-  build_run_test(has_jasmin=False)
+
+def build(ctx):
+  # Use the jasmin sources for JVM, otherwise the smali sources.
+  if os.environ["BUILD_MODE"] == "jvm":
+    ctx.default_build(has_smali=False)
+  else:
+    ctx.default_build(has_jasmin=False)
diff --git a/test/180-native-default-method/build.py b/test/180-native-default-method/build.py
index 122bcc0..46c3c5c 100644
--- a/test/180-native-default-method/build.py
+++ b/test/180-native-default-method/build.py
@@ -13,17 +13,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import subprocess, os
 
-build_run_test()
 
-if os.environ["BUILD_MODE"] != "jvm":
-  # Change the generated dex file to have a v35 magic number if it is version 38
-  with open("classes.dex", "rb+") as f:
-    assert f.read(8) == b'dex\n038\x00'
-    f.seek(0)
-    f.write(b'dex\n035\x00')
-  os.remove("180-native-default-method.jar")
-  subprocess.run([os.environ["SOONG_ZIP"], "-o",
-                  "180-native-default-method.jar", "-f", "classes.dex"], check=True)
+def build(ctx):
+  ctx.default_build()
+
+  if os.environ["BUILD_MODE"] != "jvm":
+    # Change the generated dex file to have a v35 magic number if it is version 38
+    with open("classes.dex", "rb+") as f:
+      assert f.read(8) == b"dex\n038\x00"
+      f.seek(0)
+      f.write(b"dex\n035\x00")
+    os.remove("180-native-default-method.jar")
+    cmd = [
+        os.environ["SOONG_ZIP"], "-o", "180-native-default-method.jar", "-f",
+        "classes.dex"
+    ]
+    subprocess.run(cmd, check=True)
diff --git a/test/181-default-methods/build.py b/test/181-default-methods/build.py
index 48cb485..fe1c916 100644
--- a/test/181-default-methods/build.py
+++ b/test/181-default-methods/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/1948-obsolete-const-method-handle/build.py b/test/1948-obsolete-const-method-handle/build.py
index 193aa91..9fb88b0 100644
--- a/test/1948-obsolete-const-method-handle/build.py
+++ b/test/1948-obsolete-const-method-handle/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(api_level=28)
+def build(ctx):
+  ctx.default_build(api_level=28)
diff --git a/test/1981-structural-redef-private-method-handles/build.py b/test/1981-structural-redef-private-method-handles/build.py
index d6b35b1..107499c 100644
--- a/test/1981-structural-redef-private-method-handles/build.py
+++ b/test/1981-structural-redef-private-method-handles/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/1983-structural-redefinition-failures/build.py b/test/1983-structural-redefinition-failures/build.py
index d6b35b1..107499c 100644
--- a/test/1983-structural-redefinition-failures/build.py
+++ b/test/1983-structural-redefinition-failures/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/2000-virtual-list-structural/build.py b/test/2000-virtual-list-structural/build.py
index 0d8dc0c..9f5ad44 100644
--- a/test/2000-virtual-list-structural/build.py
+++ b/test/2000-virtual-list-structural/build.py
@@ -13,11 +13,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import os
 
-build_run_test(use_desugar=False)
 
-os.rename("src-ex/java/util/AbstractCollection.bak",
-          "src-ex/java/util/AbstractCollection.java")
+def build(ctx):
+  ctx.default_build(use_desugar=False)
 
+  os.rename("src-ex/java/util/AbstractCollection.bak",
+            "src-ex/java/util/AbstractCollection.java")
diff --git a/test/2034-spaces-in-SimpleName/build.py b/test/2034-spaces-in-SimpleName/build.py
index 7601e12..ff0aba2 100644
--- a/test/2034-spaces-in-SimpleName/build.py
+++ b/test/2034-spaces-in-SimpleName/build.py
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Use API level 10000 for spaces in SimpleName
-build_run_test(use_desugar=False, api_level="10000")
+def build(ctx):
+  ctx.default_build(use_desugar=False, api_level="10000")
diff --git a/test/2038-hiddenapi-jvmti-ext/build.py b/test/2038-hiddenapi-jvmti-ext/build.py
index 8367ad0..942bb00 100644
--- a/test/2038-hiddenapi-jvmti-ext/build.py
+++ b/test/2038-hiddenapi-jvmti-ext/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
diff --git a/test/2239-varhandle-perf/build.py b/test/2239-varhandle-perf/build.py
index d6b35b1..107499c 100644
--- a/test/2239-varhandle-perf/build.py
+++ b/test/2239-varhandle-perf/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/370-dex-v37/build.py b/test/370-dex-v37/build.py
index 5ae5a03..8dcba57 100644
--- a/test/370-dex-v37/build.py
+++ b/test/370-dex-v37/build.py
@@ -13,17 +13,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import subprocess, os
 
-build_run_test()
 
-if os.environ["BUILD_MODE"] != "jvm":
-  # Change the generated dex file to have a v37 magic number if it is version 35
-  with open("classes.dex", "rb+") as f:
-    if f.read(8) == b'dex\n035\x00':
-      f.seek(0)
-      f.write(b'dex\n037\x00')
-      os.remove("370-dex-v37.jar")
-      subprocess.run([os.environ["SOONG_ZIP"], "-o",
-                      "370-dex-v37.jar", "-f", "classes.dex"], check=True)
+def build(ctx):
+  ctx.default_build()
+
+  if os.environ["BUILD_MODE"] != "jvm":
+    # Change the generated dex file to have a v37 magic number if it is version 35
+    with open("classes.dex", "rb+") as f:
+      if f.read(8) == b"dex\n035\x00":
+        f.seek(0)
+        f.write(b"dex\n037\x00")
+        os.remove("370-dex-v37.jar")
+        cmd = [
+            os.environ["SOONG_ZIP"], "-o", "370-dex-v37.jar", "-f",
+            "classes.dex"
+        ]
+        subprocess.run(cmd, check=True)
diff --git a/test/616-cha-interface-default/build.py b/test/616-cha-interface-default/build.py
index 48cb485..fe1c916 100644
--- a/test/616-cha-interface-default/build.py
+++ b/test/616-cha-interface-default/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/638-no-line-number/build.py b/test/638-no-line-number/build.py
index bc8b681..3643347 100644
--- a/test/638-no-line-number/build.py
+++ b/test/638-no-line-number/build.py
@@ -13,8 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Only keep the source name, to make sure we do remove it in the stack trace
 # when there is no line number mapping.
-build_run_test(javac_args=["-g:source"])
+def build(ctx):
+  ctx.default_build(javac_args=["-g:source"])
diff --git a/test/663-odd-dex-size2/build.py b/test/663-odd-dex-size2/build.py
index 76845c9..f304d95 100644
--- a/test/663-odd-dex-size2/build.py
+++ b/test/663-odd-dex-size2/build.py
@@ -13,4 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Nothing to do.
+
+def build(ctx):
+  pass  # Nothing to do.
diff --git a/test/663-odd-dex-size3/build.py b/test/663-odd-dex-size3/build.py
index c4fc9ee..f304d95 100644
--- a/test/663-odd-dex-size3/build.py
+++ b/test/663-odd-dex-size3/build.py
@@ -13,4 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Nothing to do
+
+def build(ctx):
+  pass  # Nothing to do.
diff --git a/test/663-odd-dex-size4/build.py b/test/663-odd-dex-size4/build.py
index c4fc9ee..f304d95 100644
--- a/test/663-odd-dex-size4/build.py
+++ b/test/663-odd-dex-size4/build.py
@@ -13,4 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Nothing to do
+
+def build(ctx):
+  pass  # Nothing to do.
diff --git a/test/674-hiddenapi/build.py b/test/674-hiddenapi/build.py
index f518d51..f8c7600 100644
--- a/test/674-hiddenapi/build.py
+++ b/test/674-hiddenapi/build.py
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test, rm
 import os
 
 # Build the jars twice. First with applying hiddenapi, creating a boot jar, then
@@ -23,14 +22,16 @@
 # hidden API access flags in dex files. DexFileVerifier is not invoked on boot
 # class path dex files, so the boot jar loads fine in the latter case.
 
-build_run_test(use_hiddenapi=True)
 
-# Move the jar file into the resource folder to be bundled with the test.
-os.mkdir("res")
-os.rename("674-hiddenapi.jar", "res/boot.jar")
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
 
-# Clear all intermediate files otherwise default-build would either skip
-# compilation or fail rebuilding.
-rm("classes*")
+  # Move the jar file into the resource folder to be bundled with the test.
+  os.mkdir("res")
+  os.rename("674-hiddenapi.jar", "res/boot.jar")
 
-build_run_test(use_hiddenapi=False)
+  # Clear all intermediate files otherwise default-build would either skip
+  # compilation or fail rebuilding.
+  ctx.bash("rm -rf classes*")
+
+  ctx.default_build(use_hiddenapi=False)
diff --git a/test/674-vdex-uncompress/build.py b/test/674-vdex-uncompress/build.py
index a694a9d..cbe1f62 100644
--- a/test/674-vdex-uncompress/build.py
+++ b/test/674-vdex-uncompress/build.py
@@ -13,8 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
 # Uncompress and align the dex files so that dex2oat will not copy the dex
 # code to the .vdex file.
-build_run_test(zip_compression_method="store", zip_align_bytes="4")
+def build(ctx):
+  ctx.default_build(zip_compression_method="store", zip_align_bytes="4")
diff --git a/test/677-fsi/build.py b/test/677-fsi/build.py
index d16a996..69afbf3 100644
--- a/test/677-fsi/build.py
+++ b/test/677-fsi/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(zip_compression_method="store", zip_align_bytes=4)
+def build(ctx):
+  ctx.default_build(zip_compression_method="store", zip_align_bytes=4)
diff --git a/test/690-hiddenapi-same-name-methods/build.py b/test/690-hiddenapi-same-name-methods/build.py
index 8367ad0..942bb00 100644
--- a/test/690-hiddenapi-same-name-methods/build.py
+++ b/test/690-hiddenapi-same-name-methods/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
diff --git a/test/691-hiddenapi-proxy/build.py b/test/691-hiddenapi-proxy/build.py
index 8367ad0..942bb00 100644
--- a/test/691-hiddenapi-proxy/build.py
+++ b/test/691-hiddenapi-proxy/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
diff --git a/test/710-varhandle-creation/build.py b/test/710-varhandle-creation/build.py
index d6b35b1..107499c 100644
--- a/test/710-varhandle-creation/build.py
+++ b/test/710-varhandle-creation/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/712-varhandle-invocations/build.py b/test/712-varhandle-invocations/build.py
index d6b35b1..107499c 100644
--- a/test/712-varhandle-invocations/build.py
+++ b/test/712-varhandle-invocations/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/713-varhandle-invokers/build.py b/test/713-varhandle-invokers/build.py
index d6b35b1..107499c 100644
--- a/test/713-varhandle-invokers/build.py
+++ b/test/713-varhandle-invokers/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/714-invoke-custom-lambda-metafactory/build.py b/test/714-invoke-custom-lambda-metafactory/build.py
index 7563062..a792b73 100644
--- a/test/714-invoke-custom-lambda-metafactory/build.py
+++ b/test/714-invoke-custom-lambda-metafactory/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_desugar=False, experimental="method-handles")
+def build(ctx):
+  ctx.default_build(use_desugar=False, experimental="method-handles")
diff --git a/test/715-clinit-implicit-parameter-annotations/build.py b/test/715-clinit-implicit-parameter-annotations/build.py
index 19c759c..0f3c108 100644
--- a/test/715-clinit-implicit-parameter-annotations/build.py
+++ b/test/715-clinit-implicit-parameter-annotations/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="parameter-annotations")
+def build(ctx):
+  ctx.default_build(experimental="parameter-annotations")
diff --git a/test/716-jli-jit-samples/build.py b/test/716-jli-jit-samples/build.py
index d6b35b1..107499c 100644
--- a/test/716-jli-jit-samples/build.py
+++ b/test/716-jli-jit-samples/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/719-varhandle-concurrency/build.py b/test/719-varhandle-concurrency/build.py
index d6b35b1..107499c 100644
--- a/test/719-varhandle-concurrency/build.py
+++ b/test/719-varhandle-concurrency/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="var-handles")
+def build(ctx):
+  ctx.default_build(experimental="var-handles")
diff --git a/test/807-method-handle-and-mr/build.py b/test/807-method-handle-and-mr/build.py
index e8e08eb..d317a1a 100644
--- a/test/807-method-handle-and-mr/build.py
+++ b/test/807-method-handle-and-mr/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/817-hiddenapi/build.py b/test/817-hiddenapi/build.py
index 1de286a..df00bb8 100644
--- a/test/817-hiddenapi/build.py
+++ b/test/817-hiddenapi/build.py
@@ -13,24 +13,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test, rm
 import os
 
-# Build the jars twice. First with applying hiddenapi, creating a boot jar, then
-# a second time without to create a normal jar. We need to do this because we
-# want to load the jar once as an app module and once as a member of the boot
-# class path. The DexFileVerifier would fail on the former as it does not allow
-# hidden API access flags in dex files. DexFileVerifier is not invoked on boot
-# class path dex files, so the boot jar loads fine in the latter case.
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  # Build the jars twice. First with applying hiddenapi, creating a boot jar, then
+  # a second time without to create a normal jar. We need to do this because we
+  # want to load the jar once as an app module and once as a member of the boot
+  # class path. The DexFileVerifier would fail on the former as it does not allow
+  # hidden API access flags in dex files. DexFileVerifier is not invoked on boot
+  # class path dex files, so the boot jar loads fine in the latter case.
 
-# Move the jar file into the resource folder to be bundled with the test.
-os.mkdir("res")
-os.rename("817-hiddenapi.jar", "res/boot.jar")
+  ctx.default_build(use_hiddenapi=True)
 
-# Clear all intermediate files otherwise default-build would either skip
-# compilation or fail rebuilding.
-rm("classes*")
+  # Move the jar file into the resource folder to be bundled with the test.
+  os.mkdir("res")
+  os.rename("817-hiddenapi.jar", "res/boot.jar")
 
-build_run_test(use_hiddenapi=False)
+  # Clear all intermediate files otherwise default-build would either skip
+  # compilation or fail rebuilding.
+  ctx.bash("rm -rf classes*")
+
+  ctx.default_build(use_hiddenapi=False)
diff --git a/test/822-hiddenapi-future/build.py b/test/822-hiddenapi-future/build.py
index 8367ad0..942bb00 100644
--- a/test/822-hiddenapi-future/build.py
+++ b/test/822-hiddenapi-future/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
diff --git a/test/948-change-annotations/build.py b/test/948-change-annotations/build.py
index f0496d7..c8f63e8 100644
--- a/test/948-change-annotations/build.py
+++ b/test/948-change-annotations/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="agents")
+def build(ctx):
+  ctx.default_build(experimental="agents")
diff --git a/test/952-invoke-custom/build.py b/test/952-invoke-custom/build.py
index ce6dd89..4fc7423 100644
--- a/test/952-invoke-custom/build.py
+++ b/test/952-invoke-custom/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_desugar=False, api_level=28)
+def build(ctx):
+  ctx.default_build(use_desugar=False, api_level=28)
diff --git a/test/953-invoke-polymorphic-compiler/build.py b/test/953-invoke-polymorphic-compiler/build.py
index e8e08eb..d317a1a 100644
--- a/test/953-invoke-polymorphic-compiler/build.py
+++ b/test/953-invoke-polymorphic-compiler/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/954-invoke-polymorphic-verifier/build.py b/test/954-invoke-polymorphic-verifier/build.py
index e8e08eb..d317a1a 100644
--- a/test/954-invoke-polymorphic-verifier/build.py
+++ b/test/954-invoke-polymorphic-verifier/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/955-methodhandles-smali/build.py b/test/955-methodhandles-smali/build.py
index e8e08eb..d317a1a 100644
--- a/test/955-methodhandles-smali/build.py
+++ b/test/955-methodhandles-smali/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/956-methodhandles/build.py b/test/956-methodhandles/build.py
index e8e08eb..d317a1a 100644
--- a/test/956-methodhandles/build.py
+++ b/test/956-methodhandles/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/957-methodhandle-transforms/build.py b/test/957-methodhandle-transforms/build.py
index e8e08eb..d317a1a 100644
--- a/test/957-methodhandle-transforms/build.py
+++ b/test/957-methodhandle-transforms/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/958-methodhandle-stackframe/build.py b/test/958-methodhandle-stackframe/build.py
index e8e08eb..d317a1a 100644
--- a/test/958-methodhandle-stackframe/build.py
+++ b/test/958-methodhandle-stackframe/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/959-invoke-polymorphic-accessors/build.py b/test/959-invoke-polymorphic-accessors/build.py
index e8e08eb..d317a1a 100644
--- a/test/959-invoke-polymorphic-accessors/build.py
+++ b/test/959-invoke-polymorphic-accessors/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="method-handles")
+def build(ctx):
+  ctx.default_build(experimental="method-handles")
diff --git a/test/960-default-smali/build.py b/test/960-default-smali/build.py
index 48cb485..fe1c916 100644
--- a/test/960-default-smali/build.py
+++ b/test/960-default-smali/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/961-default-iface-resolution-gen/build.py b/test/961-default-iface-resolution-gen/build.py
index 48cb485..fe1c916 100644
--- a/test/961-default-iface-resolution-gen/build.py
+++ b/test/961-default-iface-resolution-gen/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/962-iface-static/build.py b/test/962-iface-static/build.py
index 48cb485..fe1c916 100644
--- a/test/962-iface-static/build.py
+++ b/test/962-iface-static/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/964-default-iface-init-gen/build.py b/test/964-default-iface-init-gen/build.py
index 48cb485..fe1c916 100644
--- a/test/964-default-iface-init-gen/build.py
+++ b/test/964-default-iface-init-gen/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/968-default-partial-compile-gen/build.py b/test/968-default-partial-compile-gen/build.py
index e4416ec..0200c99 100644
--- a/test/968-default-partial-compile-gen/build.py
+++ b/test/968-default-partial-compile-gen/build.py
@@ -13,8 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import os
 
-if os.environ["BUILD_MODE"] != "jvm":
-  build_run_test(experimental="default-methods")
+
+def build(ctx):
+  if os.environ["BUILD_MODE"] != "jvm":
+    ctx.default_build(experimental="default-methods")
diff --git a/test/969-iface-super/build.py b/test/969-iface-super/build.py
index 48cb485..fe1c916 100644
--- a/test/969-iface-super/build.py
+++ b/test/969-iface-super/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/970-iface-super-resolution-gen/build.py b/test/970-iface-super-resolution-gen/build.py
index 48cb485..fe1c916 100644
--- a/test/970-iface-super-resolution-gen/build.py
+++ b/test/970-iface-super-resolution-gen/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/971-iface-super/build.py b/test/971-iface-super/build.py
index e4416ec..0200c99 100644
--- a/test/971-iface-super/build.py
+++ b/test/971-iface-super/build.py
@@ -13,8 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 import os
 
-if os.environ["BUILD_MODE"] != "jvm":
-  build_run_test(experimental="default-methods")
+
+def build(ctx):
+  if os.environ["BUILD_MODE"] != "jvm":
+    ctx.default_build(experimental="default-methods")
diff --git a/test/975-iface-private/build.py b/test/975-iface-private/build.py
index 48cb485..fe1c916 100644
--- a/test/975-iface-private/build.py
+++ b/test/975-iface-private/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/978-virtual-interface/build.py b/test/978-virtual-interface/build.py
index 48cb485..fe1c916 100644
--- a/test/978-virtual-interface/build.py
+++ b/test/978-virtual-interface/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(experimental="default-methods")
+def build(ctx):
+  ctx.default_build(experimental="default-methods")
diff --git a/test/979-const-method-handle/build.py b/test/979-const-method-handle/build.py
index 193aa91..9fb88b0 100644
--- a/test/979-const-method-handle/build.py
+++ b/test/979-const-method-handle/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(api_level=28)
+def build(ctx):
+  ctx.default_build(api_level=28)
diff --git a/test/999-redefine-hiddenapi/build.py b/test/999-redefine-hiddenapi/build.py
index 8367ad0..942bb00 100644
--- a/test/999-redefine-hiddenapi/build.py
+++ b/test/999-redefine-hiddenapi/build.py
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from art_build_rules import build_run_test
 
-build_run_test(use_hiddenapi=True)
+def build(ctx):
+  ctx.default_build(use_hiddenapi=True)
diff --git a/test/Android.bp b/test/Android.bp
index 3830f9a..c62c45b 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -1889,7 +1889,6 @@
         "art_build_rules.py",
         "run-test-build.py",
         "buildfailures.json",
-        "etc/default-build.py",
         "etc/default-check",
         "etc/default-run",
         "etc/run-test-jar",
diff --git a/test/art_build_rules.py b/test/art_build_rules.py
index 765289d..b1e81be 100644
--- a/test/art_build_rules.py
+++ b/test/art_build_rules.py
@@ -44,7 +44,8 @@
       else:
         os.remove(path)
 
-def build_run_test(
+def default_build(
+    ctx,
     use_desugar=True,
     use_hiddenapi=True,
     need_dex=None,
diff --git a/test/etc/default-build.py b/test/etc/default-build.py
deleted file mode 100644
index 7a229c7..0000000
--- a/test/etc/default-build.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright (C) 2022 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.
-
-from art_build_rules import build_run_test
-
-build_run_test()
diff --git a/test/run-test-build.py b/test/run-test-build.py
index fa9073b..e3d2d13 100755
--- a/test/run-test-build.py
+++ b/test/run-test-build.py
@@ -23,9 +23,18 @@
 import art_build_rules
 from importlib.machinery import SourceFileLoader
 
+import art_build_rules
+
 ZIP = "prebuilts/build-tools/linux-x86/bin/soong_zip"
 BUILDFAILURES = json.loads(open(os.path.join("art", "test", "buildfailures.json"), "rt").read())
 
+class BuildTestContext:
+  def bash(self, cmd):
+    return subprocess.run(cmd, shell=True, check=True)
+
+  def default_build(self, **kwargs):
+    art_build_rules.default_build(self, **kwargs)
+
 def copy_sources(args, tmp, mode, srcdir):
   """Copy test files from Android tree into the build sandbox and return its path."""
 
@@ -43,7 +52,7 @@
   shutil.copytree(srcdir, dstdir)
 
   # Copy the default scripts if the test does not have a custom ones.
-  for name in ["build.py", "run", "check"]:
+  for name in ["run", "check"]:
     src, dst = f"art/test/etc/default-{name}", join(dstdir, name)
     if os.path.exists(dst):
       shutil.copy2(src, dstdir)  # Copy default script next to the custom script.
@@ -93,7 +102,13 @@
   os.chdir(dstdir)
   for name, value in env.items():
     os.environ[name] = str(value)
-  SourceFileLoader("build_" + test_name, join(dstdir, "build.py")).load_module()
+  ctx = BuildTestContext()
+  script = pathlib.Path(join(dstdir, "build.py"))
+  if script.exists():
+    module = SourceFileLoader("build_" + test_name, str(script)).load_module()
+    module.build(ctx)
+  else:
+    art_build_rules.default_build(ctx)
 
 # 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.