aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--README.md138
-rw-r--r--src/vogar/Dexer.java1
-rw-r--r--src/vogar/Run.java4
-rw-r--r--src/vogar/Toolchain.java6
-rw-r--r--src/vogar/Vogar.java21
-rw-r--r--src/vogar/android/AndroidSdk.java76
-rw-r--r--src/vogar/android/DeviceRuntime.java14
-rw-r--r--src/vogar/android/InstallApkTask.java2
-rw-r--r--src/vogar/commands/Command.java1
-rw-r--r--src/vogar/tasks/BuildActionTask.java10
-rw-r--r--test/vogar/android/AbstractModeTest.java4
-rw-r--r--test/vogar/android/HostRuntimeLocalTargetTest.java8
-rw-r--r--test/vogar/target/junit3/TestMethodWithParameterTest.java2
-rw-r--r--test/vogar/target/testng/ChangeDefaultLocaleTest.java1
-rw-r--r--test/vogar/target/testng/TestNgAnnotationsClass.java45
-rw-r--r--test/vogar/target/testng/TestNgAnnotationsMethod.java45
-rw-r--r--test/vogar/target/testng/TestRunnerTestNgTest.java62
18 files changed, 384 insertions, 59 deletions
diff --git a/Android.mk b/Android.mk
index 51e3464..6bf77fe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -31,14 +31,13 @@ LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_STATIC_JAVA_LIBRARIES := \
caliper \
caliper-gson \
- guavalib \
+ guava \
junit \
testng \
vogar-jsr305 \
vogar-kxml-libcore-20110123
LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(HOST_OUT_EXECUTABLES)/dx \
$(HOST_OUT_EXECUTABLES)/d8 \
$(HOST_OUT_JAVA_LIBRARIES)/desugar.jar
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8a6ec19
--- /dev/null
+++ b/README.md
@@ -0,0 +1,138 @@
+# Vogar
+
+Vogar is a generic code/test/benchmark runner tool for Android. It is
+primarily used to run libcore and art tests and benchmarks, however
+this tool can also run arbitrary Java files either on host or target
+device.
+
+Vogar supports multiple testing frameworks and configurations:
+
+ * Allows running JUnit tests, TestNG tests, jtreg tests, Caliper
+ benchmarks or executable Java classes. It supports running
+ fine-grained tests that can be specified with hash symbol, e.g.
+ "com.android.Test#test".
+
+ * Allows running tests and benchmarks using five available runtime
+ modes: `activity`, `app_process`, `device`, `host` or `jvm`.
+
+## Building and running
+
+First build it:
+
+* With a minimal `aosp/master-art` tree:
+```bash
+export SOONG_ALLOW_MISSING_DEPENDENCIES=true
+${ANDROID_BUILD_TOP}/art/tools/buildbot-build.sh --target
+```
+
+* With a full Android (AOSP) `aosp/master` tree:
+```bash
+m vogar
+```
+
+## Features
+
+Vogar supports running tests and/or benchmarks (called "actions" below in the document)
+in five different modes (specified with `--mode` option). An "action" is a `.java` file,
+directory or class names:
+
+ 1. Activity (`--mode=activity`)
+
+ Vogar runs given action in the context of an [`android.app.Activity`](https://developer.android.com/reference/android/app/Activity) on a device.
+
+ 2. App (`--mode=app_process`)
+
+ Vogar runs given action in an app_process runtime on a device or emulator.
+ Used in conjunction with the `--benchmark` option for running Caliper benchmarks.
+ This is required to benchmark any code relying on the android framework.
+
+ ```bash
+ Vogar --mode app_process --benchmark frameworks/base/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
+ ```
+
+3. Device (`--mode=device`)
+
+ Vogar runs given action in an ART runtime on a device or emulator.
+
+4. Host (`--mode=host`)
+
+ Vogar runs in an ART runtime on the local machine built with any lunch combo.
+ Similar to "Device" mode but running local ART.
+
+5. JVM (`--mode=jvm`)
+
+ Vogar runs given action in a Java VM on the local machine.
+
+Most frequently you will use either `--mode=device` or `--mode=host` mode.
+
+## Testing and debugging
+
+Vogar has unit test coverage around basic functionality. Most of the coverage
+is for [JUnit](https://junit.org/) and [TestNG](https://testng.org/) integration.
+
+### Building and running
+
+First, build tests with:
+```bash
+m vogar-tests
+```
+
+Run all tests using phony make target with:
+```bash
+m run-vogar-tests
+```
+
+Or run manually (if you want to specify a subset of all unit tests, for example):
+```bash
+java -cp ${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/vogar-tests.jar \
+ org.junit.runner.JUnitCore vogar.AllTests
+```
+
+## Architecture and implementation
+
+High level model of each Vogar run is:
+
+ 1. Parsing input options.
+ 2. Creating a list of `Task` objects that encapsulate various steps required.
+ These `Task` objects can depend on each other, and get executed only if all
+ dependencies are already executed.
+ 3. Executing tasks. It include assembling the code, dexing it, packing in
+ an activity/runnable dex jar, preparing the environment (host or device),
+ pushing all artifacts, and running it.
+
+### Classes overview
+
+The basic building block of Vogar execution is the `Task` class. There are several
+sub classes of `Task`, for example:
+
+ * `MkdirTask`
+ * `RmTask`
+ * `PrepareTarget`
+
+The `Target` class encapsulates the runtime environment, for example a
+remote device or the local host. There are four available environments:
+
+ * `AdbTarget` is used when `--mode=device` is set.
+
+ It makes sure device is connected, required directories are mount
+ properly, and all required files are synced to the device.
+
+ * `AdbChrootTarget` is used when `--mode=device --chroot=/data/chroot/`
+ are set.
+
+ Same as `AdbTarget` but relatively to a specified chroot directory
+ (instead of the whole system under the root directory on the device).
+
+ * `LocalTarget` is used when `--mode=host` or `--mode=jvm` are set.
+
+ Same as `AdbTarget` but runs on the host machine.
+
+ * `SshTarget` is used when `--ssh <host:port>` is set.
+
+ Same as `LocalTarget` but on a remote machine at the given address.
+
+After parsing command line options, Vogar builds a list of tasks which
+are put in a `TaskQueue`. They are executed using all available cores
+except when "Activity" mode is enabled -- in that case it is always one
+thread.
+
diff --git a/src/vogar/Dexer.java b/src/vogar/Dexer.java
index 0e38715..3bf50f0 100644
--- a/src/vogar/Dexer.java
+++ b/src/vogar/Dexer.java
@@ -20,6 +20,5 @@ package vogar;
* Available tools for generating dex files
*/
public enum Dexer {
- DX,
D8,
}
diff --git a/src/vogar/Run.java b/src/vogar/Run.java
index ba36594..402b1c4 100644
--- a/src/vogar/Run.java
+++ b/src/vogar/Run.java
@@ -106,6 +106,8 @@ public final class Run {
public final boolean checkJni;
public final boolean debugging;
public final Integer sdkVersion;
+ public final boolean serialDexing;
+ public final boolean verboseDexStats;
public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir,
AndroidSdk androidSdk, Rm rm, Target target, File runnerDir)
@@ -186,6 +188,8 @@ public final class Run {
this.checkJni = vogar.checkJni;
this.debugging = (vogar.debugPort != null) || vogar.debugApp;
this.sdkVersion = vogar.sdkVersion;
+ this.serialDexing = vogar.serialDexing;
+ this.verboseDexStats = vogar.verboseDexStats;
}
private Mode createMode(ModeId modeId, Variant variant) {
diff --git a/src/vogar/Toolchain.java b/src/vogar/Toolchain.java
index b19d2cb..1d8189d 100644
--- a/src/vogar/Toolchain.java
+++ b/src/vogar/Toolchain.java
@@ -19,17 +19,13 @@ package vogar;
import vogar.Dexer;
public enum Toolchain {
- // .dex: desugar + javac + dx
- DX,
// .dex: desugar + javac + d8
D8,
// .class: javac
JAVAC;
public Dexer getDexer() {
- if (this == Toolchain.DX) {
- return Dexer.DX;
- } else if (this == Toolchain.D8) {
+ if (this == Toolchain.D8) {
return Dexer.D8;
}
throw new IllegalStateException("No dexer for toolchain " + this);
diff --git a/src/vogar/Vogar.java b/src/vogar/Vogar.java
index 59a0616..7fba4aa 100644
--- a/src/vogar/Vogar.java
+++ b/src/vogar/Vogar.java
@@ -221,6 +221,12 @@ public final class Vogar {
@Option(names = {"--sdk-version"})
Integer sdkVersion = 28;
+ @Option(names = {"--serial-dexing"})
+ boolean serialDexing = false;
+
+ @Option(names = {"--verbose-dex-stats"})
+ boolean verboseDexStats = false;
+
@VisibleForTesting public Vogar() {}
private void printUsage() {
@@ -254,7 +260,7 @@ public final class Vogar {
System.out.println(" DEFAULT: default (or N/A), X32: 32-bit, X64: 64-bit");
System.out.println(" Default is: " + variant);
System.out.println();
- System.out.println(" --toolchain <DX|D8|JAVAC>: Which toolchain to use.");
+ System.out.println(" --toolchain <D8|JAVAC>: Which toolchain to use.");
System.out.println(" Default depends on --mode value (currently "
+ modeId.defaultToolchain() + " for --mode=" + modeId + ")");
System.out.println();
@@ -327,6 +333,17 @@ public final class Vogar {
System.out.println();
System.out.println(" --verbose: turn on persistent verbose output.");
System.out.println();
+ System.out.println(" --serial-dexing: disallow Vogar spawn multiple simultaneous dex tasks");
+ System.out.println(" Enabling this is useful when there is a memory constraint;");
+ System.out.println(" and each dex task could easily consume around 1.5G of memory.");
+ System.out.println(" Default is: " + serialDexing);
+ System.out.println();
+ System.out.println(" --verbose-dex-stats: print verbose stats of used resources by dex tasks");
+ System.out.println(" Enabling this wraps each dex task in '/usr/bin/time -v' call");
+ System.out.println(" and adds its output to the stdout log. Useful to get a sense of");
+ System.out.println(" resource usage such as RSS memory, CPU usage and wall-clock time.");
+ System.out.println(" Default is: " + verboseDexStats);
+ System.out.println();
System.out.println(" --check-jni: enable CheckJNI mode.");
System.out.println(" See http://developer.android.com/training/articles/perf-jni.html.");
System.out.println(" Default is: " + checkJni + ", but disabled for --benchmark.");
@@ -666,7 +683,7 @@ public final class Vogar {
AndroidSdk androidSdk = null;
if (modeId.requiresAndroidSdk()) {
androidSdk = AndroidSdk.createAndroidSdk(console, mkdir, modeId, language,
- !actionFiles.isEmpty());
+ !actionFiles.isEmpty(), serialDexing, verboseDexStats);
}
if (runnerType == null) {
diff --git a/src/vogar/android/AndroidSdk.java b/src/vogar/android/AndroidSdk.java
index 15c936d..220e6a6 100644
--- a/src/vogar/android/AndroidSdk.java
+++ b/src/vogar/android/AndroidSdk.java
@@ -43,12 +43,11 @@ import vogar.util.Strings;
/**
- * Android SDK commands such as adb, aapt and dx.
+ * Android SDK commands such as adb, aapt and d8.
*/
public class AndroidSdk {
private static final String D8_COMMAND_NAME = "d8";
- private static final String DX_COMMAND_NAME = "dx";
private static final String ARBITRARY_BUILD_TOOL_NAME = D8_COMMAND_NAME;
private final Log log;
@@ -58,6 +57,8 @@ public class AndroidSdk {
private final String desugarJarPath;
private final Md5Cache dexCache;
private final Language language;
+ private final boolean serialDexing;
+ private final boolean verboseDexStats;
public static Collection<File> defaultExpectations() {
return Collections.singletonList(new File("libcore/expectations/knownfailures.txt"));
@@ -71,7 +72,7 @@ public class AndroidSdk {
*/
public static AndroidSdk createAndroidSdk(
Log log, Mkdir mkdir, ModeId modeId, Language language,
- boolean supportBuildFromSource) {
+ boolean supportBuildFromSource, boolean serialDexing, boolean verboseDexStats) {
List<String> path = new Command.Builder(log).args("which", ARBITRARY_BUILD_TOOL_NAME)
.permitNonZeroExitStatus(true)
.execute();
@@ -99,7 +100,7 @@ public class AndroidSdk {
* Android build tree (target):
* ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/aapt
* ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/adb
- * ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/dx
+ * ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/d8
* ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/desugar.jar
* ${ANDROID_BUILD_TOP}/out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates
* /classes.jar
@@ -220,7 +221,7 @@ public class AndroidSdk {
}
return new AndroidSdk(log, mkdir, compilationClasspath, androidJarPath, desugarJarPath,
- new HostFileCache(log, mkdir), language);
+ new HostFileCache(log, mkdir), language, serialDexing, verboseDexStats);
}
/** Logs jars that couldn't be found ands suggests a command for building them */
@@ -261,7 +262,8 @@ public class AndroidSdk {
@VisibleForTesting
AndroidSdk(Log log, Mkdir mkdir, File[] compilationClasspath, String androidJarPath,
- String desugarJarPath, HostFileCache hostFileCache, Language language) {
+ String desugarJarPath, HostFileCache hostFileCache, Language language,
+ boolean serialDexing, boolean verboseDexStats) {
this.log = log;
this.mkdir = mkdir;
this.compilationClasspath = compilationClasspath;
@@ -269,6 +271,8 @@ public class AndroidSdk {
this.desugarJarPath = desugarJarPath;
this.dexCache = new Md5Cache(log, "dex", hostFileCache);
this.language = language;
+ this.serialDexing = serialDexing;
+ this.verboseDexStats = verboseDexStats;
}
// Goes up N levels in the filesystem hierarchy. Return the last file that exists if this goes
@@ -374,37 +378,28 @@ public class AndroidSdk {
* same package they're testing, even when that's a core
* library package. If you're actually just using this tool to
* execute arbitrary code, this has the unfortunate
- * side-effect of preventing "dx" from protecting you from
+ * side-effect of preventing "d8" from protecting you from
* yourself.
- *
- * Memory options pulled from build/core/definitions.mk to
- * handle large dx input when building dex for APK.
*/
Command.Builder builder = new Command.Builder(log);
+ if (verboseDexStats) {
+ builder.args("/usr/bin/time").args("-v");
+ }
switch (dexer) {
- case DX:
- builder.args(DX_COMMAND_NAME);
- builder.args("-JXms16M").args("-JXmx1536M");
- builder.args("--min-sdk-version=" + language.getMinApiLevel());
- if (multidex) {
- builder.args("--multi-dex");
- }
- builder.args("--dex")
- .args("--output=" + output)
- .args("--core-library")
- .args(filePaths);
- builder.execute();
- break;
case D8:
List<String> sanitizedOutputFilePaths;
try {
- sanitizedOutputFilePaths = removeDexFilesForD8(filePaths);
+ sanitizedOutputFilePaths = removeDexFilesForD8(filePaths, outputTempDir);
} catch (IOException e) {
throw new RuntimeException("Error while removing dex files from archive", e);
}
builder.args(D8_COMMAND_NAME);
builder.args("-JXms16M").args("-JXmx1536M");
+ builder.args("-JXX:+TieredCompilation").args("-JXX:TieredStopAtLevel=1");
+ builder.args("-JDcom.android.tools.r8.emitRecordAnnotationsInDex");
+ builder.args("-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex");
+ builder.args("--thread-count").args("1");
// d8 will not allow compiling with a single dex file as the target, but if given
// a directory name will start its output in classes.dex but may overflow into
@@ -473,26 +468,35 @@ public class AndroidSdk {
}
/**
+ * Generates a file path for a modified d8 input file.
+ * @param inputFile the d8 input file.
+ * @param outputDirectory the directory where the modified file should be written.
+ * @return the destination for the modified d8 input file.
+ */
+ private static File getModifiedD8Destination(File inputFile, File outputDirectory) {
+ String name = inputFile.getName();
+ int suffixStart = name.lastIndexOf('.');
+ if (suffixStart != -1) {
+ name = name.substring(0, suffixStart);
+ }
+ return new File(outputDirectory, name + "-d8.jar");
+ }
+
+ /**
* Removes DEX files from an archive and preserves the rest.
*/
- private List<String> removeDexFilesForD8(List<String> fileNames) throws IOException {
+ private List<String> removeDexFilesForD8(List<String> fileNames, File tempDir)
+ throws IOException {
byte[] buffer = new byte[4096];
List<String> processedFiles = new ArrayList<>(fileNames.size());
for (String inputFileName : fileNames) {
- String jarExtension = ".jar";
- String outputFileName;
- if (inputFileName.endsWith(jarExtension)) {
- outputFileName =
- inputFileName.substring(0, inputFileName.length() - jarExtension.length())
- + "-d8" + jarExtension;
- } else {
- outputFileName = inputFileName + "-d8" + jarExtension;
- }
+ File inputFile = new File(inputFileName);
+ File outputFile = getModifiedD8Destination(inputFile, tempDir);
try (JarOutputStream outputJar =
- new JarOutputStream(new FileOutputStream(outputFileName))) {
+ new JarOutputStream(new FileOutputStream(outputFile))) {
copyJarContentExcludingFiles(buffer, inputFileName, outputJar, ".dex");
}
- processedFiles.add(outputFileName);
+ processedFiles.add(outputFile.toString());
}
return processedFiles;
}
diff --git a/src/vogar/android/DeviceRuntime.java b/src/vogar/android/DeviceRuntime.java
index 1c85793..2b5f01f 100644
--- a/src/vogar/android/DeviceRuntime.java
+++ b/src/vogar/android/DeviceRuntime.java
@@ -25,7 +25,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import vogar.Action;
-import vogar.Toolchain;
import vogar.Variant;
import vogar.Classpath;
import vogar.Mode;
@@ -56,10 +55,18 @@ public final class DeviceRuntime implements Mode {
@Override public Set<Task> installTasks() {
Set<Task> result = new HashSet<Task>();
+ Task lastDexTask = null;
// dex everything on the classpath and push it to the device.
for (File classpathElement : run.classpath.getElements()) {
- addCreateDexJarAndPushTasks(result, run.basenameOfJar(classpathElement),
+ Task currentDexTask = addCreateDexJarAndPushTasks(result, run.basenameOfJar(classpathElement),
classpathElement, null);
+ // If {@code serialDexing} is enabled, make each subsequent dex task
+ // depend on previous so any moment of time only one dexer (d8) instance is run
+ // simultaneously.
+ if (lastDexTask != null && run.serialDexing) {
+ currentDexTask.afterSuccess(lastDexTask);
+ }
+ lastDexTask = currentDexTask;
}
return result;
}
@@ -131,7 +138,7 @@ public final class DeviceRuntime implements Mode {
return result;
}
- private void addCreateDexJarAndPushTasks(
+ private Task addCreateDexJarAndPushTasks(
Set<Task> tasks, String name, File jar, Action action) {
File localDex = run.localDexFile(name);
File localTempDir = run.localDir(name);
@@ -140,6 +147,7 @@ public final class DeviceRuntime implements Mode {
localTempDir);
tasks.add(createDexJarTask);
tasks.add(run.target.pushTask(localDex, deviceDex).afterSuccess(createDexJarTask));
+ return createDexJarTask;
}
private Task newCreateDexJarTask(Classpath classpath, File classpathElement, String name,
diff --git a/src/vogar/android/InstallApkTask.java b/src/vogar/android/InstallApkTask.java
index a62e85a..7186392 100644
--- a/src/vogar/android/InstallApkTask.java
+++ b/src/vogar/android/InstallApkTask.java
@@ -47,7 +47,7 @@ public final class InstallApkTask extends Task {
// We can't just give dex multiple jars with conflicting class names
// With that in mind, the APK packaging strategy is as follows:
- // 1. dx to create a dex
+ // 1. d8 to create a dex
// 2. aapt the dex to create apk
// 3. sign the apk
// 4. install the apk
diff --git a/src/vogar/commands/Command.java b/src/vogar/commands/Command.java
index 38fdf24..6c5c4b9 100644
--- a/src/vogar/commands/Command.java
+++ b/src/vogar/commands/Command.java
@@ -131,6 +131,7 @@ public final class Command {
int exitValue = process.waitFor();
destroyed = true;
if (exitValue != 0 && !permitNonZeroExitStatus) {
+ outputLines.add("Command exited with code: " + exitValue);
throw new CommandFailedException(args, outputLines);
}
diff --git a/src/vogar/tasks/BuildActionTask.java b/src/vogar/tasks/BuildActionTask.java
index fd4c43a..04605fd 100644
--- a/src/vogar/tasks/BuildActionTask.java
+++ b/src/vogar/tasks/BuildActionTask.java
@@ -17,6 +17,7 @@
package vogar.tasks;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -90,7 +91,14 @@ public final class BuildActionTask extends Task {
if (run.debugging) {
javac.debug();
}
- if (javaFile != null) {
+ if (javaFile == null) {
+ if (JAVA_SOURCE_PATTERN.matcher(action.getTargetClass()).find()) {
+ // This is likely a missing source file rather than a class
+ // named something.java....
+ throw new FileNotFoundException("Unlikely classname, assuming missing source file: "
+ + action.getTargetClass());
+ }
+ } else {
if (!JAVA_SOURCE_PATTERN.matcher(javaFile.toString()).find()) {
throw new CommandFailedException(Collections.<String>emptyList(),
Collections.singletonList("Cannot compile: " + javaFile));
diff --git a/test/vogar/android/AbstractModeTest.java b/test/vogar/android/AbstractModeTest.java
index 225883c..f6f379a 100644
--- a/test/vogar/android/AbstractModeTest.java
+++ b/test/vogar/android/AbstractModeTest.java
@@ -73,7 +73,7 @@ public abstract class AbstractModeTest {
androidSdk = new AndroidSdk(console, mkdir,
new File[] {new File("classpath")}, "android.jar", "desugar.jar",
new HostFileCache(console, mkdir),
- Language.CUR);
+ Language.CUR, false, false);
Target target = createTarget();
final Vogar vogar = new Vogar();
@@ -83,7 +83,7 @@ public abstract class AbstractModeTest {
+ ". Please check stdout.");
}
- run = new Run(vogar, Toolchain.DX, console, mkdir, androidSdk, new Rm(console), target,
+ run = new Run(vogar, Toolchain.D8, console, mkdir, androidSdk, new Rm(console), target,
new File("runner/dir"));
classpath = new Classpath();
diff --git a/test/vogar/android/HostRuntimeLocalTargetTest.java b/test/vogar/android/HostRuntimeLocalTargetTest.java
index 45a147a..a6fbd02 100644
--- a/test/vogar/android/HostRuntimeLocalTargetTest.java
+++ b/test/vogar/android/HostRuntimeLocalTargetTest.java
@@ -87,11 +87,11 @@ public class HostRuntimeLocalTargetTest extends AbstractModeTest {
+ " -Xbootclasspath"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-oj-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-libart-hostdex.jar"
- + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-icu4j-hostdex.jar"
- + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/okhttp-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/bouncycastle-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/apache-xml-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-icu4j-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ " -Duser.language=en"
+ " -Duser.region=US"
+ " -Xcheck:jni"
@@ -149,11 +149,11 @@ public class HostRuntimeLocalTargetTest extends AbstractModeTest {
+ " -Xbootclasspath"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-oj-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-libart-hostdex.jar"
- + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-icu4j-hostdex.jar"
- + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/okhttp-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/bouncycastle-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/apache-xml-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-icu4j-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ " -Duser.language=en"
+ " -Duser.region=US"
+ " -Xjnigreflimit:2000"
diff --git a/test/vogar/target/junit3/TestMethodWithParameterTest.java b/test/vogar/target/junit3/TestMethodWithParameterTest.java
index e345e17..28fd255 100644
--- a/test/vogar/target/junit3/TestMethodWithParameterTest.java
+++ b/test/vogar/target/junit3/TestMethodWithParameterTest.java
@@ -20,7 +20,7 @@ import junit.framework.TestCase;
public class TestMethodWithParameterTest extends TestCase {
- @SuppressWarnings("unused")
+ @SuppressWarnings({"unused", "JUnit3TestNotRun"})
public void testParameterized(int i) {
}
}
diff --git a/test/vogar/target/testng/ChangeDefaultLocaleTest.java b/test/vogar/target/testng/ChangeDefaultLocaleTest.java
index 1833ff2..1465f33 100644
--- a/test/vogar/target/testng/ChangeDefaultLocaleTest.java
+++ b/test/vogar/target/testng/ChangeDefaultLocaleTest.java
@@ -20,7 +20,6 @@ import static org.testng.Assert.assertEquals;
import java.util.Locale;
import org.testng.annotations.Test;
-;
/**
* Verify that the locale is reset to Locale.US before/after each test is run.
diff --git a/test/vogar/target/testng/TestNgAnnotationsClass.java b/test/vogar/target/testng/TestNgAnnotationsClass.java
new file mode 100644
index 0000000..3a28151
--- /dev/null
+++ b/test/vogar/target/testng/TestNgAnnotationsClass.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package vogar.target.testng;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class TestNgAnnotationsClass {
+ @BeforeClass
+ public void beforeClass() {
+ System.out.println("@BeforeClass");
+ }
+
+ @AfterClass
+ public void afterClass() {
+ System.out.println("@AfterClass");
+ }
+
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+
+ @Test
+ public void test3() {
+ }
+}
diff --git a/test/vogar/target/testng/TestNgAnnotationsMethod.java b/test/vogar/target/testng/TestNgAnnotationsMethod.java
new file mode 100644
index 0000000..12840c8
--- /dev/null
+++ b/test/vogar/target/testng/TestNgAnnotationsMethod.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package vogar.target.testng;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.AfterMethod;
+
+public class TestNgAnnotationsMethod {
+ @BeforeMethod
+ public void beforeMethod() {
+ System.out.println("@BeforeMethod");
+ }
+
+ @AfterMethod
+ public void afterMethod() {
+ System.out.println("@AfterMethod");
+ }
+
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+
+ @Test
+ public void test3() {
+ }
+}
diff --git a/test/vogar/target/testng/TestRunnerTestNgTest.java b/test/vogar/target/testng/TestRunnerTestNgTest.java
index 060244e..c1f1cb1 100644
--- a/test/vogar/target/testng/TestRunnerTestNgTest.java
+++ b/test/vogar/target/testng/TestRunnerTestNgTest.java
@@ -77,4 +77,66 @@ public class TestRunnerTestNgTest extends AbstractTestRunnerTest {
.completedNormally();
}
+ @TestRunnerProperties(testClass = TestNgAnnotationsMethod.class)
+ @Test
+ public void testRunner_TestNgAnnotationsMethod_OneMethod() throws Exception {
+ String[] args = {"test1"};
+ TestRunner runner = testRunnerRule.createTestRunner(args);
+ runner.run();
+
+ expectedResults()
+ .text("@BeforeMethod\n")
+ .success("test1")
+ .text("@AfterMethod\n")
+ .completedNormally();
+ }
+
+ @TestRunnerProperties(testClass = TestNgAnnotationsMethod.class)
+ @Test
+ public void testRunner_TestNgAnnotationsMethod_AllMethods() throws Exception {
+ TestRunner runner = testRunnerRule.createTestRunner();
+ runner.run();
+
+ expectedResults()
+ .text("@BeforeMethod\n")
+ .success("test1")
+ .text("@AfterMethod\n")
+ .text("@BeforeMethod\n")
+ .success("test2")
+ .text("@AfterMethod\n")
+ .text("@BeforeMethod\n")
+ .success("test3")
+ .text("@AfterMethod\n")
+ .completedNormally();
+ }
+
+ @TestRunnerProperties(testClass = TestNgAnnotationsClass.class)
+ @Test
+ public void testRunner_TestNgAnnotationsClass_OneMethod() throws Exception {
+ String[] args = {"test1"};
+ TestRunner runner = testRunnerRule.createTestRunner(args);
+ runner.run();
+
+ expectedResults()
+ .text("@BeforeClass\n")
+ .success("test1")
+ .text("@AfterClass\n")
+ .completedNormally();
+ }
+
+ @TestRunnerProperties(testClass = TestNgAnnotationsClass.class)
+ @Test
+ public void testRunner_TestNgAnnotationsClass_AllMethods() throws Exception {
+ TestRunner runner = testRunnerRule.createTestRunner();
+ runner.run();
+
+ expectedResults()
+ .text("@BeforeClass\n")
+ .success("test1")
+ .success("test2")
+ .success("test3")
+ .text("@AfterClass\n")
+ .completedNormally();
+ }
+
}