diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:47:09 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:47:09 +0000 |
commit | b04bfb42b99744eeecad46c0f56e37a01f543edd (patch) | |
tree | c17317e718ada6f5cc43e86d859522c5bcda6fd5 | |
parent | 728069a04599352d12c89c61c91d757c0ffb607c (diff) | |
parent | cf50f7f9bfae65aab4d924d17dec99be5a922999 (diff) | |
download | vogar-aml_tz3_314012010.tar.gz |
Snap for 8730993 from cf50f7f9bfae65aab4d924d17dec99be5a922999 to mainline-tzdata3-releaseaml_tz3_314012070aml_tz3_314012050aml_tz3_314012010aml_tz3_313110000aml_tz3_312511020aml_tz3_312511010aml_tz3_312410020aml_tz3_312410010android12-mainline-tzdata3-releaseaml_tz3_314012010
Change-Id: I6963d3f476b26fc8e93c994bbf8ef2c95c39a837
21 files changed, 144 insertions, 761 deletions
@@ -33,7 +33,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ caliper-gson \ guavalib \ junit \ - testng \ vogar-jsr305 \ vogar-kxml-libcore-20110123 @@ -1,2 +1,5 @@ -# Bug component: 24949 -include platform/libcore:/OWNERS +android-libcore-team+review@google.com +dsrbecky@google.com +ngeoffray@google.com +paulduffin@google.com +rpl@google.com diff --git a/src/vogar/ModeId.java b/src/vogar/ModeId.java index c918104..613722a 100644 --- a/src/vogar/ModeId.java +++ b/src/vogar/ModeId.java @@ -35,35 +35,31 @@ public enum ModeId { /** * $BOOTCLASSPATH for art+libcore only. * (Intended for use with dalvikvm only.) + * See TARGET_TEST_CORE_JARS in android/art/build/Android.common_path.mk */ private static final String[] DEVICE_JARS = new String[] { - // ART module BCP libraries. See CORE_IMG_JARS in art/build/Android.common_path.mk. "core-oj", "core-libart", + "core-icu4j", + "conscrypt", "okhttp", "bouncycastle", "apache-xml", - // Stubs for dependencies from other APEX modules. If tests require it, this could use - // platform (xxx.module.platform.api.stubs) or even intra-core - // (xxx.module.intra.core.api.stubs) API stubs. However it's currently not necessary, so - // let's stick to public APIs for hygiene. - "i18n.module.public.api.stubs", - "conscrypt.module.public.api.stubs", }; /** * $BOOTCLASSPATH for art+libcore only (host version). * (Intended for use with dalvikvm only.) - * See HOST_TEST_CORE_JARS in art/build/Android.common_path.mk + * See HOST_TEST_CORE_JARS in android/art/build/Android.common_path.mk */ private static final String[] HOST_JARS = new String[] { "core-oj-hostdex", "core-libart-hostdex", + "core-icu4j-hostdex", + "conscrypt-hostdex", "okhttp-hostdex", "bouncycastle-hostdex", "apache-xml-hostdex", - "core-icu4j-hostdex", - "conscrypt-hostdex", }; /** diff --git a/src/vogar/Run.java b/src/vogar/Run.java index ba36594..4a61a76 100644 --- a/src/vogar/Run.java +++ b/src/vogar/Run.java @@ -105,7 +105,6 @@ public final class Run { public final Toolchain toolchain; public final boolean checkJni; public final boolean debugging; - public final Integer sdkVersion; public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir, AndroidSdk androidSdk, Rm rm, Target target, File runnerDir) @@ -185,7 +184,6 @@ public final class Run { this.taskQueue = new TaskQueue(console, maxConcurrentActions); this.checkJni = vogar.checkJni; this.debugging = (vogar.debugPort != null) || vogar.debugApp; - this.sdkVersion = vogar.sdkVersion; } private Mode createMode(ModeId modeId, Variant variant) { diff --git a/src/vogar/RunnerType.java b/src/vogar/RunnerType.java index 938898a..dfc8c5a 100644 --- a/src/vogar/RunnerType.java +++ b/src/vogar/RunnerType.java @@ -21,40 +21,33 @@ package vogar; */ public enum RunnerType { /** - * Runs JUnit classes, TestNG classes and classes with a main(String[] args) method. + * Runs both JUnit classes and classes with a main(String[] args) method. */ - DEFAULT(false, true, true, true), + DEFAULT(false, true, true), /** * Runs only Caliper benchmarks. */ - CALIPER(true, false, false, false), + CALIPER(true, false, false), /** * Runs only JUnit classes. */ - JUNIT(false, true, false, false), + JUNIT(false, true, false), /** * Runs only classes with a main(String[] args) method. */ - MAIN(false, false, true, false), - - /** - * Runs only TestNG classes. - */ - TESTNG(false, false, false, true); + MAIN(false, false, true); private final boolean supportsCaliper; private final boolean supportsJUnit; private final boolean supportsMain; - private final boolean supportsTestNg; - RunnerType(boolean supportsCaliper, boolean supportsJUnit, boolean supportsMain, boolean supportsTestNg) { + RunnerType(boolean supportsCaliper, boolean supportsJUnit, boolean supportsMain) { this.supportsCaliper = supportsCaliper; this.supportsJUnit = supportsJUnit; this.supportsMain = supportsMain; - this.supportsTestNg = supportsTestNg; } public boolean supportsCaliper() { @@ -68,8 +61,4 @@ public enum RunnerType { public boolean supportsMain() { return supportsMain; } - - public boolean supportsTestNg() { - return supportsTestNg; - } } diff --git a/src/vogar/Vogar.java b/src/vogar/Vogar.java index 59a0616..a7f3272 100644 --- a/src/vogar/Vogar.java +++ b/src/vogar/Vogar.java @@ -40,7 +40,7 @@ import vogar.util.Strings; * Command line interface for running benchmarks and tests on dalvik. */ public final class Vogar { - static final int LARGE_TIMEOUT_MULTIPLIER = 20; + static final int LARGE_TIMEOUT_MULTIPLIER = 10; public static final int NUM_PROCESSORS = Runtime.getRuntime().availableProcessors(); private final List<File> actionFiles = new ArrayList<File>(); @@ -218,9 +218,6 @@ public final class Vogar { @Option(names = {"--runner-type"}) RunnerType runnerType; - @Option(names = {"--sdk-version"}) - Integer sdkVersion = 28; - @VisibleForTesting public Vogar() {} private void printUsage() { @@ -230,10 +227,10 @@ public final class Vogar { System.out.println("Usage: Vogar [options]... <actions>... [-- target args]..."); System.out.println(); System.out.println(" <actions>: .java files, directories, or class names."); - System.out.println(" These should be JUnit tests, TestNG tests, jtreg tests, Caliper benchmarks"); + System.out.println(" These should be JUnit tests, jtreg tests, Caliper benchmarks"); System.out.println(" or executable Java classes."); System.out.println(); - System.out.println(" When passing in a JUnit or TestNG test class, it may have \"#method_name\""); + System.out.println(" When passing in a JUnit test class, it may have \"#method_name\""); System.out.println(" appended to it, to specify a single test method."); System.out.println(); System.out.println(" [target args]: arguments passed to the target process. This is only useful when"); @@ -311,12 +308,11 @@ public final class Vogar { System.out.println(" --results-dir <directory>: read and write (if --record-results used)"); System.out.println(" results from and to this directory."); System.out.println(); - System.out.println(" --runner-type <default|caliper|main|junit|testng>: specify which runner to use."); - System.out.println(" default: runs JUnit tests, TestNG tests and main() classes"); + System.out.println(" --runner-type <default|caliper|main|junit>: specify which runner to use."); + System.out.println(" default: runs both JUnit tests and main() classes"); System.out.println(" caliper: runs Caliper benchmarks only"); System.out.println(" main: runs main() classes only"); System.out.println(" junit: runs JUnit tests only"); - System.out.println(" testng: runs TestNG tests only"); System.out.println(" Default is determined by --benchmark and --testonly, if they are"); System.out.println(" not specified then defaults to: default"); System.out.println(); @@ -407,11 +403,6 @@ public final class Vogar { System.out.println(" Disable with --no-multidex."); System.out.println(" Default is: " + multidex); System.out.println(); - System.out.println(" --sdk-version <argument>: min and target sdk version."); - System.out.println(" Used in the app manifest for ACTIVITY mode"); - System.out.println(" to prevent warning popups about old applications"); - System.out.println(" Default is: " + sdkVersion); - System.out.println(); System.out.println(" --dalvik-cache <argument>: override default dalvik-cache location."); System.out.println(" Default is: " + dalvikCache); System.out.println(); @@ -665,8 +656,7 @@ public final class Vogar { AndroidSdk androidSdk = null; if (modeId.requiresAndroidSdk()) { - androidSdk = AndroidSdk.createAndroidSdk(console, mkdir, modeId, language, - !actionFiles.isEmpty()); + androidSdk = AndroidSdk.createAndroidSdk(console, mkdir, modeId, language); } if (runnerType == null) { diff --git a/src/vogar/android/AndroidSdk.java b/src/vogar/android/AndroidSdk.java index 15c936d..45f11bb 100644 --- a/src/vogar/android/AndroidSdk.java +++ b/src/vogar/android/AndroidSdk.java @@ -70,8 +70,7 @@ public class AndroidSdk { * compilation class path and android jar path. */ public static AndroidSdk createAndroidSdk( - Log log, Mkdir mkdir, ModeId modeId, Language language, - boolean supportBuildFromSource) { + Log log, Mkdir mkdir, ModeId modeId, Language language) { List<String> path = new Command.Builder(log).args("which", ARBITRARY_BUILD_TOOL_NAME) .permitNonZeroExitStatus(true) .execute(); @@ -176,43 +175,47 @@ public class AndroidSdk { desugarJarPath = desugarJar.getPath(); - if (!supportBuildFromSource) { - compilationClasspath = new File[]{}; - } else { - String pattern = outDir + - "target/common/obj/JAVA_LIBRARIES/%s_intermediates/classes"; + String pattern = outDir + + "target/common/obj/JAVA_LIBRARIES/%s_intermediates/classes"; + if (modeId.isHost()) { + pattern = outDir + "host/common/obj/JAVA_LIBRARIES/%s_intermediates/classes"; + } + pattern += ".jar"; + + String[] jarNames = modeId.getJarNames(); + compilationClasspath = new File[jarNames.length]; + for (int i = 0; i < jarNames.length; i++) { + String jar = jarNames[i]; + File file; if (modeId.isHost()) { - pattern = outDir + "host/common/obj/JAVA_LIBRARIES/%s_intermediates/classes"; - } - pattern += ".jar"; - - String[] jarNames = modeId.getJarNames(); - compilationClasspath = new File[jarNames.length]; - List<String> missingJars = new ArrayList<>(); - for (int i = 0; i < jarNames.length; i++) { - String jar = jarNames[i]; - File file; - if (modeId.isHost()) { - if ("conscrypt-hostdex".equals(jar)) { - jar = "conscrypt-host-hostdex"; - } else if ("core-icu4j-hostdex".equals(jar)) { - jar = "core-icu4j-host-hostdex"; - } - file = new File(String.format(pattern, jar)); + if ("conscrypt-hostdex".equals(jar)) { + jar = "conscrypt-host-hostdex"; + } else if ("core-icu4j-hostdex".equals(jar)) { + jar = "core-icu4j-host-hostdex"; + } + file = new File(String.format(pattern, jar)); + } else { + final String apexPackage; + // With unbundled ART, the intermediate directory storing the jar file + // outside ART APEX doesn't contain the apex package name. + final boolean tryNonApexIntermediate; + if ("conscrypt".equals(jar)) { + apexPackage = "com.android.conscrypt"; + tryNonApexIntermediate = true; + } else if ("core-icu4j".equals(jar)) { + apexPackage = "com.android.i18n"; + tryNonApexIntermediate = true; } else { - file = findApexJar(jar, pattern); - if (file.exists()) { - log.verbose("Using jar " + jar + " from " + file); - } else { - missingJars.add(jar); - } + apexPackage = "com.android.art.testing"; + tryNonApexIntermediate = false; + } + + file = new File(String.format(pattern, jar + "." + apexPackage)); + if (tryNonApexIntermediate && !file.exists()) { + file = new File(String.format(pattern, jar)); } - compilationClasspath[i] = file; - } - if (!missingJars.isEmpty()) { - logMissingJars(log, missingJars); - throw new RuntimeException("Unable to locate all jars needed for compilation"); } + compilationClasspath[i] = file; } } else { throw new RuntimeException("Couldn't derive Android home from " @@ -223,42 +226,6 @@ public class AndroidSdk { new HostFileCache(log, mkdir), language); } - /** Logs jars that couldn't be found ands suggests a command for building them */ - private static void logMissingJars(Log log, List<String> missingJars) { - StringBuilder makeCommand = new StringBuilder().append("m "); - for (String jarName : missingJars) { - String apex = apexForJar(jarName); - log.warn("Missing compilation jar " + jarName + - (apex != null ? " from APEX " + apex : "")); - makeCommand.append(jarName).append(" "); - } - log.info("Suggested make command: " + makeCommand); - } - - /** Returns the name of the APEX a particular jar might be located in */ - private static String apexForJar(String jar) { - if (jar.endsWith(".api.stubs")) { - return null; // API stubs aren't in any APEX. - } - return "com.android.art.testing"; - } - - /** - * Depending on the build setup, jars might be located in the intermediates directory - * for their APEX or not, so look in both places. Returns the last path searched, so - * always non-null but possibly non-existent and so the caller should check. - */ - private static File findApexJar(String jar, String filePattern) { - String apex = apexForJar(jar); - if (apex != null) { - File file = new File(String.format(filePattern, jar + "." + apex)); - if (file.exists()) { - return file; - } - } - return new File(String.format(filePattern, jar)); - } - @VisibleForTesting AndroidSdk(Log log, Mkdir mkdir, File[] compilationClasspath, String androidJarPath, String desugarJarPath, HostFileCache hostFileCache, Language language) { @@ -364,10 +331,9 @@ public class AndroidSdk { } } - List<String> filePaths = new ArrayList<String>(); - for (File file : classpath.getElements()) { - filePaths.add(file.getPath()); - } + // Call desugar first to remove invoke-dynamic LambdaMetaFactory usage, + // which ART doesn't support. + List<String> desugarOutputFilePaths = desugar(outputTempDir, classpath, dependentCp); /* * We pass --core-library so that we can write tests in the @@ -393,42 +359,26 @@ public class AndroidSdk { builder.args("--dex") .args("--output=" + output) .args("--core-library") - .args(filePaths); + .args(desugarOutputFilePaths); builder.execute(); break; case D8: - List<String> sanitizedOutputFilePaths; + List<String> sanitizedDesugarOutputFilePaths; try { - sanitizedOutputFilePaths = removeDexFilesForD8(filePaths); + sanitizedDesugarOutputFilePaths = removeDexFilesForD8(desugarOutputFilePaths); } catch (IOException e) { throw new RuntimeException("Error while removing dex files from archive", e); } builder.args(D8_COMMAND_NAME); builder.args("-JXms16M").args("-JXmx1536M"); - - // 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 - // multiple dex files. See b/189327238 - String outputPath = output.toString(); - String dexOverflowPath = null; - if (outputPath.endsWith("/classes.dex")) { - dexOverflowPath = outputPath.replace("classes.dex", "classes2.dex"); - outputPath = output.getParentFile().toString(); - } builder .args("--min-api").args(language.getMinApiLevel()) - .args("--output").args(outputPath) - .args(sanitizedOutputFilePaths); + .args("--output").args(output) + .args(sanitizedDesugarOutputFilePaths); builder.execute(); - if (dexOverflowPath != null && new File(dexOverflowPath).exists()) { - // If we were expecting a single dex file and d8 overflows into two - // or more files than fail. - throw new RuntimeException("Dex file overflow " + dexOverflowPath - + ", try --multidex"); - } if (output.toString().endsWith(".jar")) { try { - fixD8JarOutput(output, filePaths); + fixD8JarOutput(output, desugarOutputFilePaths); } catch (IOException e) { throw new RuntimeException("Error while fixing d8 output", e); } @@ -473,7 +423,7 @@ public class AndroidSdk { } /** - * Removes DEX files from an archive and preserves the rest. + * Removes DEX files from an archive and preserve the rest. */ private List<String> removeDexFilesForD8(List<String> fileNames) throws IOException { byte[] buffer = new byte[4096]; @@ -486,7 +436,7 @@ public class AndroidSdk { inputFileName.substring(0, inputFileName.length() - jarExtension.length()) + "-d8" + jarExtension; } else { - outputFileName = inputFileName + "-d8" + jarExtension; + outputFileName = inputFileName + "-d8" + jarExtension; } try (JarOutputStream outputJar = new JarOutputStream(new FileOutputStream(outputFileName))) { @@ -531,6 +481,73 @@ public class AndroidSdk { } } + // Runs desugar on classpath as the input with dependentCp as the classpath_entry. + // Returns the generated output list of files. + private List<String> desugar(File outputTempDir, Classpath classpath, Classpath dependentCp) { + Command.Builder builder = new Command.Builder(log) + .args("java", "-jar", desugarJarPath); + + // Ensure that libcore is on the bootclasspath for desugar, + // otherwise it tries to use the java command's bootclasspath. + for (File f : compilationClasspath) { + builder.args("--bootclasspath_entry", f.getPath()); + } + + // Desugar needs to actively resolve classes that the original inputs + // were compiled against. Dx does not; so it doesn't use dependentCp. + for (File f : dependentCp.getElements()) { + builder.args("--classpath_entry", f.getPath()); + } + + builder.args("--core_library") + .args("--min_sdk_version", language.getMinApiLevel()); + + // Build the -i (input) and -o (output) arguments. + // Every input from classpath corresponds to a new output temp file into + // desugarTempDir. + File desugarTempDir; + { + // Generate a temporary list of files that correspond to the 'classpath'; + // desugar will then convert the files in 'classpath' into 'desugarClasspath'. + if (!outputTempDir.isDirectory()) { + throw new AssertionError( + "outputTempDir must be a directory: " + outputTempDir.getPath()); + } + + String desugarTempDirPath = outputTempDir.getPath() + "/desugar"; + desugarTempDir = new File(desugarTempDirPath); + desugarTempDir.mkdirs(); + if (!desugarTempDir.exists()) { + throw new AssertionError( + "desugarTempDir; failed to create " + desugarTempDirPath); + } + } + + // Create unique file names to support non-unique classpath base names. + // + // For example: + // + // Classpath("/x/y.jar:/z/y.jar:/a/b.jar") -> + // Output Files("${tmp}/0y.jar:${tmp}/1y.jar:${tmp}/2b.jar") + int uniqueCounter = 0; + List<String> desugarOutputFilePaths = new ArrayList<String>(); + + for (File desugarInput : classpath.getElements()) { + String tmpName = uniqueCounter + desugarInput.getName(); + ++uniqueCounter; + + String desugarOutputPath = desugarTempDir.getPath() + "/" + tmpName; + desugarOutputFilePaths.add(desugarOutputPath); + + builder.args("-i", desugarInput.getPath()) + .args("-o", desugarOutputPath); + } + + builder.execute(); + + return desugarOutputFilePaths; + } + public void packageApk(File apk, File manifest) { new Command(log, "aapt", "package", diff --git a/src/vogar/android/InstallApkTask.java b/src/vogar/android/InstallApkTask.java index a62e85a..8e2479d 100644 --- a/src/vogar/android/InstallApkTask.java +++ b/src/vogar/android/InstallApkTask.java @@ -83,8 +83,6 @@ public final class InstallApkTask extends Task { "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"" + packageName(action) + "\">\n" + " <uses-permission android:name=\"android.permission.INTERNET\" />\n" + - " <uses-sdk android:minSdkVersion=\"" + run.sdkVersion + "\"\n" + - " android:targetSdkVersion=\"" + run.sdkVersion + "\" />\n" + " <application" + ((run.debugging) ? " android:debuggable=\"true\"" : "") + ">\n" + " <activity android:name=\"" + ACTIVITY_CLASS + "\">\n" + @@ -116,11 +114,10 @@ public final class InstallApkTask extends Task { * According to android.content.pm.PackageParser, package name * "must have at least one '.' separator" Since the qualified name * may not contain a dot, we prefix containing one to ensure we - * are compliant. Also transform any hyphens to underscores as they - * are illegal in package names. + * are compliant. */ public static String packageName(Action action) { - return "vogar.test." + action.getName().replaceAll("-", "_"); + return "vogar.test." + action.getName(); } private void signApk(File apkUnsigned) { diff --git a/src/vogar/commands/Command.java b/src/vogar/commands/Command.java index 38fdf24..60c30b7 100644 --- a/src/vogar/commands/Command.java +++ b/src/vogar/commands/Command.java @@ -205,8 +205,8 @@ public final class Command { log.verbose("sending quit signal to command " + Command.this); sendQuitSignal(process); - // hard kill in 1 minute - timeoutNanoTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(60); + // hard kill in 2 seconds + timeoutNanoTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(2); new TimeoutTask() { @Override protected void onTimeout(Process process) { log.verbose("killing timed out command " + Command.this); diff --git a/src/vogar/target/TestRunner.java b/src/vogar/target/TestRunner.java index 7edc5b5..58137fd 100644 --- a/src/vogar/target/TestRunner.java +++ b/src/vogar/target/TestRunner.java @@ -17,6 +17,7 @@ package vogar.target; import com.google.common.annotations.VisibleForTesting; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; @@ -34,7 +35,6 @@ import vogar.RunnerType; import vogar.TestProperties; import vogar.monitor.TargetMonitor; import vogar.target.junit.JUnitRunnerFactory; -import vogar.target.testng.TestNgRunnerFactory; /** * Runs an action, in process on the target. @@ -88,9 +88,6 @@ public final class TestRunner { if (runnerType.supportsMain()) { runnerFactories.add(new MainRunnerFactory()); } - if (runnerType.supportsTestNg()) { - runnerFactories.add(new TestNgRunnerFactory()); - } runnerFactory = new CompositeRunnerFactory(runnerFactories); this.monitorPort = monitorPort; diff --git a/src/vogar/target/testng/TestEnvironmentListener.java b/src/vogar/target/testng/TestEnvironmentListener.java deleted file mode 100644 index 7ae9088..0000000 --- a/src/vogar/target/testng/TestEnvironmentListener.java +++ /dev/null @@ -1,54 +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. - */ -package vogar.target.testng; - -import org.testng.ITestContext; -import org.testng.ITestListener; -import org.testng.ITestResult; - -import vogar.target.TestEnvironment; - -public class TestEnvironmentListener implements ITestListener { - - private final TestEnvironment environment; - - public TestEnvironmentListener(TestEnvironment environment) { - this.environment = environment; - } - - @Override - public void onTestStart(ITestResult result) { - environment.reset(); - } - - @Override - public void onTestSuccess(ITestResult result) {} - - @Override - public void onTestFailure(ITestResult result) {} - - @Override - public void onTestSkipped(ITestResult result) {} - - @Override - public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} - - @Override - public void onStart(ITestContext context) {} - - @Override - public void onFinish(ITestContext context) {} -} diff --git a/src/vogar/target/testng/TestNg.java b/src/vogar/target/testng/TestNg.java deleted file mode 100644 index f2dbd43..0000000 --- a/src/vogar/target/testng/TestNg.java +++ /dev/null @@ -1,48 +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. - */ - -package vogar.target.testng; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; - -public final class TestNg { - private TestNg() {} - - public static boolean isTestNgTest(Class<?> klass) { - // Classes annotated with @Test - for (Annotation a : klass.getAnnotations()) { - Class<?> annotationClass = a.annotationType(); - - if (org.testng.annotations.Test.class.isAssignableFrom(annotationClass)) { - return true; - } - } - - // Methods annotated with @Test - for (Method m : klass.getMethods()) { - for (Annotation a : m.getAnnotations()) { - Class<?> annotationClass = a.annotationType(); - - if (org.testng.annotations.Test.class.isAssignableFrom(annotationClass)) { - return true; - } - } - } - - return false; - } -} diff --git a/src/vogar/target/testng/TestNgAnnotationTransformer.java b/src/vogar/target/testng/TestNgAnnotationTransformer.java deleted file mode 100644 index a0e9862..0000000 --- a/src/vogar/target/testng/TestNgAnnotationTransformer.java +++ /dev/null @@ -1,98 +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. - */ -package vogar.target.testng; - -import org.testng.IAnnotationTransformer; -import org.testng.annotations.ITestAnnotation; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -/** - * A {@link IAnnotationTransformer} that: - * - * <ul> - * <li>Handles vogar {@code --timeout} option and overrides test run timeout if necessary. - * <li>Skips past (discards) all tests up to and including one that failed previously causing the - * process to exit. - * <p>If {@link #skipReference} has a null value then this lets all tests run. Otherwise, this - * filters out all tests up to and including the one whose name matches the value in the - * reference at which point the reference is set to null, so all following tests are kept. - * This class is a TestNG-version of {@link vogar.target.SkipPastFilter} which handles {@code - * --skipPast} VM flag the same way. - * </ul> - * - * @see vogar.Vogar - */ -public class TestNgAnnotationTransformer implements IAnnotationTransformer { - - private final long timeoutMillis; - private final AtomicReference<String> skipReference; - private final String qualification; - private final HashSet<String> args; - - public TestNgAnnotationTransformer( - int timeoutSeconds, - AtomicReference<String> skipReference, - String qualification, - String[] vogarArgs) { - this.timeoutMillis = 1000L * timeoutSeconds; - this.skipReference = skipReference; - this.qualification = qualification; - this.args = new HashSet<>(); - this.args.addAll(List.of(vogarArgs)); - } - - @Override - public void transform( - ITestAnnotation annotation, - Class testClass, - Constructor testConstructor, - Method testMethod) { - // Use the least timeout between vogar --timeout and @Test(timeout = N) annotation. - if (timeoutMillis > 0) { - long testTimeout = annotation.getTimeOut(); - if (testTimeout > timeoutMillis) { - annotation.setTimeOut(timeoutMillis); - } - } - - // Skip up to and including given test name if --skipPast provided. - final String skipPast = skipReference.get(); - if (skipPast != null && testClass == null && testMethod != null) { - String name = testMethod.getName(); - if (skipPast.equals(name)) { - skipReference.set(null); - } - annotation.setEnabled(false); - } - - // Disable all but specified tests if qualified test name provided (package.class#method). - if (qualification != null && testMethod != null) { - if (!qualification.equals(testMethod.getName())) { - annotation.setEnabled(false); - } - } - if (!args.isEmpty() && testMethod != null) { - if (!args.contains(testMethod.getName())) { - annotation.setEnabled(false); - } - } - } -} diff --git a/src/vogar/target/testng/TestNgListenerAdapter.java b/src/vogar/target/testng/TestNgListenerAdapter.java deleted file mode 100644 index 6f02c20..0000000 --- a/src/vogar/target/testng/TestNgListenerAdapter.java +++ /dev/null @@ -1,72 +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. - */ -package vogar.target.testng; - -import org.testng.ITestContext; -import org.testng.ITestListener; -import org.testng.ITestResult; - -import vogar.Result; -import vogar.monitor.TargetMonitor; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -public class TestNgListenerAdapter implements ITestListener { - - private final TargetMonitor monitor; - - public TestNgListenerAdapter(TargetMonitor monitor) { - this.monitor = monitor; - } - - @Override - public void onTestStart(ITestResult result) { - StringBuilder sb = new StringBuilder(); - sb.append(result.getTestClass().getName()); - if (result.getName() != null) { - sb.append('#').append(result.getName()); - } - monitor.outcomeStarted(sb.toString()); - } - - @Override - public void onTestSuccess(ITestResult result) { - monitor.outcomeFinished(Result.SUCCESS); - } - - @Override - public void onTestFailure(ITestResult result) { - Throwable thrown = result.getThrowable(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream stackTrace = new PrintStream(out); - thrown.printStackTrace(stackTrace); - monitor.output(out.toString()); - monitor.outcomeFinished(Result.ERROR); - } - - @Override - public void onTestSkipped(ITestResult result) {} - - @Override - public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} - - @Override - public void onStart(ITestContext context) {} - - @Override - public void onFinish(ITestContext context) {} -} diff --git a/src/vogar/target/testng/TestNgRunnerFactory.java b/src/vogar/target/testng/TestNgRunnerFactory.java deleted file mode 100644 index 2e214fd..0000000 --- a/src/vogar/target/testng/TestNgRunnerFactory.java +++ /dev/null @@ -1,56 +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. - */ -package vogar.target.testng; - -import vogar.monitor.TargetMonitor; -import vogar.target.RunnerFactory; -import vogar.target.TargetRunner; -import vogar.target.TestEnvironment; - -import java.util.concurrent.atomic.AtomicReference; - -import javax.annotation.Nullable; - -public class TestNgRunnerFactory implements RunnerFactory { - - @Nullable - @Override - public TargetRunner newRunner( - TargetMonitor monitor, - String qualification, - Class<?> klass, - AtomicReference<String> skipPastReference, - TestEnvironment testEnvironment, - int timeoutSeconds, - String[] args) { - if (supports(klass)) { - return new TestNgTargetRunner( - monitor, - skipPastReference, - testEnvironment, - timeoutSeconds, - klass, - qualification, - args); - } else { - return null; - } - } - - private static boolean supports(Class<?> klass) { - return TestNg.isTestNgTest(klass); - } -} diff --git a/src/vogar/target/testng/TestNgTargetRunner.java b/src/vogar/target/testng/TestNgTargetRunner.java deleted file mode 100644 index 6b10509..0000000 --- a/src/vogar/target/testng/TestNgTargetRunner.java +++ /dev/null @@ -1,86 +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. - */ -package vogar.target.testng; - -import org.testng.TestNG; - -import vogar.monitor.TargetMonitor; -import vogar.target.TargetRunner; -import vogar.target.TestEnvironment; - -import java.util.concurrent.atomic.AtomicReference; - -public class TestNgTargetRunner implements TargetRunner { - - private final TargetMonitor monitor; - private final Class<?> testClass; - private final TestEnvironment testEnvironment; - private final String qualification; - private final TestNgAnnotationTransformer transformer; - private final String[] args; - - public TestNgTargetRunner( - TargetMonitor monitor, - AtomicReference<String> skipPastReference, - TestEnvironment testEnvironment, - int timeoutSeconds, - Class<?> testClass, - String qualification, - String[] args) { - this.monitor = monitor; - this.testClass = testClass; - this.testEnvironment = testEnvironment; - this.qualification = qualification; - this.args = args; - this.transformer = - new TestNgAnnotationTransformer( - timeoutSeconds, skipPastReference, qualification, args); - } - - @Override - public boolean run() { - // Set up TestNg core infrastructure. - TestNG testng = new TestNG(false); - - // This transformer handles test timeout and overrides it if vogar was run - // with specific timeout parameter (see --timeout option). - testng.setAnnotationTransformer(transformer); - - // Disable parallel execution of tests using @DataProvider's. - // If parallel execution is enabled with @DataProvider(..., parallel = true) then it - // would break vogar.monitor.HostMonitor#followProcess protocol which relies on receiving - // control messages in specific order. It expects "{outcome: ...}" json-object - // followed by another "{result: ...}" json-object for each test run; whereas with parallel - // execution enabled for @DataProvider, HostMonitor#followProcess would receive all - // "outcome" objects, and then all "result" objects, in random order. - // The easiest way of preventing this behavior would be to disable parallel execution - // for data providers. - testng.setDataProviderThreadCount(1); - - // Make TestNG less noisy. - testng.setVerbose(0); - // Proxy to pass TestNg test lifecycle calls to vogar. - TestNgListenerAdapter adapter = new TestNgListenerAdapter(monitor); - testng.addListener(adapter); - // Listener that resets environment for each test. - testng.addListener(new TestEnvironmentListener(testEnvironment)); - - testng.setTestClasses(new Class[] {testClass}); - - testng.run(); - return true; - } -} diff --git a/test/vogar/target/AllTargetTests.java b/test/vogar/target/AllTargetTests.java index e687c1b..113cb72 100644 --- a/test/vogar/target/AllTargetTests.java +++ b/test/vogar/target/AllTargetTests.java @@ -22,7 +22,6 @@ import org.junit.runners.Suite.SuiteClasses; import vogar.target.caliper.AllCaliperTests; import vogar.target.junit.AllJUnitTests; import vogar.target.main.AllMainTests; -import vogar.target.testng.AllTestNgTests; /** * Run the tests in this package. @@ -33,7 +32,6 @@ import vogar.target.testng.AllTestNgTests; AllCaliperTests.class, AllJUnitTests.class, AllMainTests.class, - AllTestNgTests.class, }) @RunWith(Suite.class) public class AllTargetTests { diff --git a/test/vogar/target/testng/AllTestNgTests.java b/test/vogar/target/testng/AllTestNgTests.java deleted file mode 100644 index 70caab9..0000000 --- a/test/vogar/target/testng/AllTestNgTests.java +++ /dev/null @@ -1,31 +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. - */ - -package vogar.target.testng; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -/** - * Run the tests in this package. - */ -@SuiteClasses({ - TestRunnerTestNgTest.class, -}) -@RunWith(Suite.class) -public class AllTestNgTests { -} diff --git a/test/vogar/target/testng/ChangeDefaultLocaleTest.java b/test/vogar/target/testng/ChangeDefaultLocaleTest.java deleted file mode 100644 index 1833ff2..0000000 --- a/test/vogar/target/testng/ChangeDefaultLocaleTest.java +++ /dev/null @@ -1,43 +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. - */ - -package vogar.target.testng; - -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. - * - * <p>This ensures that the {@link vogar.target.TestEnvironment} class is used correctly. - */ -public class ChangeDefaultLocaleTest { - - @Test - public void testDefault_Locale_CANADA() { - assertEquals(Locale.getDefault(), Locale.US); - Locale.setDefault(Locale.CANADA); - } - - @Test - public void testDefault_Locale_CHINA() { - assertEquals(Locale.getDefault(), Locale.US); - Locale.setDefault(Locale.CHINA); - } -} diff --git a/test/vogar/target/testng/SimpleTest.java b/test/vogar/target/testng/SimpleTest.java deleted file mode 100644 index ab9603c..0000000 --- a/test/vogar/target/testng/SimpleTest.java +++ /dev/null @@ -1,33 +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. - */ - -package vogar.target.testng; - -import org.testng.annotations.Test; - -public class SimpleTest { - @Test - public void simple1() { - } - - @Test - public void simple2() { - } - - @Test - public void Simple3() { - } -} diff --git a/test/vogar/target/testng/TestRunnerTestNgTest.java b/test/vogar/target/testng/TestRunnerTestNgTest.java deleted file mode 100644 index 060244e..0000000 --- a/test/vogar/target/testng/TestRunnerTestNgTest.java +++ /dev/null @@ -1,80 +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. - */ - -package vogar.target.testng; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import vogar.target.AbstractTestRunnerTest; -import vogar.target.TestRunner; -import vogar.target.TestRunnerProperties; - -/** - * Tests for using TestRunner to run TestNG classes. - */ -@RunWith(JUnit4.class) -public class TestRunnerTestNgTest extends AbstractTestRunnerTest { - - @TestRunnerProperties(testClass = ChangeDefaultLocaleTest.class) - @Test - public void testRunner_ChangeDefaultLocaleTest() throws Exception { - TestRunner runner = testRunnerRule.createTestRunner(); - runner.run(); - - expectedResults() - .success("testDefault_Locale_CANADA") - .success("testDefault_Locale_CHINA") - .completedNormally(); - } - - @TestRunnerProperties(testClass = SimpleTest.class) - @Test - public void testRunner_SkipPastAll() throws Exception { - Class<?> testClass = testRunnerRule.testClass(); - String failingTestName = testClass.getName() + "#other"; - TestRunner runner = testRunnerRule.createTestRunner("--skipPast", failingTestName); - - runner.run(); - expectedResults().completedNormally(); - } - - @TestRunnerProperties(testClass = SimpleTest.class) - @Test - public void testRunner_SimpleTest2_OneMethod() throws Exception { - String[] args = {"simple2"}; - TestRunner runner = testRunnerRule.createTestRunner(args); - runner.run(); - - expectedResults() - .success("simple2") - .completedNormally(); - } - - @TestRunnerProperties(testClass = SimpleTest.class) - @Test - public void testRunner_SimpleTest2_TwoMethod() throws Exception { - String[] args = {"simple1", "Simple3"}; - TestRunner runner = testRunnerRule.createTestRunner(args); - runner.run(); - - expectedResults() - .success("Simple3") - .success("simple1") - .completedNormally(); - } - -} |