/* * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package test.com.sun.max.vm.compiler; import java.io.*; import java.util.*; import test.com.sun.max.vm.jtrun.*; import com.sun.max.io.*; import com.sun.max.io.Streams.Redirector; import com.sun.max.profile.*; import com.sun.max.program.*; import com.sun.max.program.option.*; import com.sun.max.test.*; import com.sun.max.util.*; import com.sun.max.vm.*; import com.sun.max.vm.hosted.*; public final class JavaTester { private JavaTester() { } public static final OptionSet options = new OptionSet(true); private static final Option<Boolean> HELP = options.newBooleanOption("help", false, "Displays usage message and exits."); private static final Option<Integer> VERBOSE = options.newIntegerOption("verbose", 1, "Selects the verbosity level of the testing framework."); private static final Option<Boolean> LOADING_PACKAGES = options.newBooleanOption("loadPackages", false, "Determines whether the Java prototype is to load all VM packages."); private static final Option<List<String>> EXECS = options.newStringListOption("scenario", "reflect", "Selects the scenarios in which to run each test."); private static final Option<Boolean> GEN_RUNSCHEME = options.newBooleanOption("gen-run-scheme", true, "Selects whether the java tester will generate a run scheme for the " + "tests, which can be used to create a target VM to run."); private static final Option<String> RUNSCHEME_PACKAGE = options.newStringOption("run-scheme-package", "some", "Selects the target output package for the tests."); private static final Option<Boolean> GEN_IMAGE = options.newBooleanOption("gen-image", false, "Selects whether the tester will generate a boot image with the specified tests."); private static final Option<Boolean> RUN_IMAGE = options.newBooleanOption("run-image", false, "Selects whether the tester will run the target VM that has been generated."); private static final Option<Boolean> RESTART_IMAGE = options.newBooleanOption("restart", true, "Selects whether the tester will generate an image that allows restarting the tests " + "from a particular test number."); private static final Option<Boolean> SORT_OPTION = options.newBooleanOption("alphabetical", true, "Selects whether the tester will sort the tests alphabetically when generating an image."); private static final Option<List<String>> GEN_IMAGE_ARGS = options.newStringListOption("gen-image-args", "", "Additional args to pass to the image generator."); private static final Option<List<String>> GEN_IMAGE_PROPS = options.newStringListOption("gen-image-props", "", "Additional system properties to pass to the image generator."); private static final Option<List<String>> RUN_IMAGE_ARGS = options.newStringListOption("run-image-args", "", "Additional args to pass to the target image."); private static final Option<Boolean> NATIVE_TESTS = options.newBooleanOption("native-tests", false, "When specified, the JavaTester will attempt to load " + System.mapLibraryName("javatest") + " in order to run " + "native JNI and JVM tests."); private static final Option<Boolean> REPORT_METRICS = options.newBooleanOption("report-metrics", false, "When specified, the JavaTester will report metrics that were gathered while running " + "the tests."); private static final Option<String> FILTER = options.newStringOption("filter", null, "When specified, the JavaTester will only run tests that match (contains) this filter. Start filter with ~ to use a regex instead of 'contains'"); private static boolean filesUpdated = false; public static void main(String[] args) throws IOException, InterruptedException { Trace.addTo(options); // parse the arguments final String[] arguments = options.parseArguments(args).getArguments(); if (SORT_OPTION.getValue()) { Arrays.sort(arguments); } if (HELP.getValue()) { options.printHelp(System.out, 80); return; } // create a registry of known VM executors. final Registry<JavaExecHarness.Executor> executors = Registry.newRegistry(JavaExecHarness.Executor.class); if (NATIVE_TESTS.getValue()) { if (MaxineVM.isHosted()) { Prototype.loadLibrary("javatest"); } else { System.loadLibrary("javatest"); } } executors.registerClass("reflect", ReflectiveExecutor.class); // run each executor. for (String alias : EXECS.getValue()) { if ("target".equals(alias)) { runInTarget(arguments); } else { runExecutor(alias, arguments, executors); } } if (REPORT_METRICS.getValue()) { GlobalMetrics.report(System.out); } // If JavaTesterGenerator had to actually update if (filesUpdated) { System.exit(1); } } private static void runInTarget(final String[] arguments) throws IOException, InterruptedException { if (GEN_RUNSCHEME.getValue()) { // generate the run scheme if necessary Trace.line(0, "Generating target run scheme..."); options.setValue("restart", String.valueOf(RESTART_IMAGE.getValue())); options.setValue("alphabetical", String.valueOf(SORT_OPTION.getValue())); options.setValue("package", String.valueOf(RUNSCHEME_PACKAGE.getValue())); filesUpdated = JTGenerator.generate(options, arguments); } if (GEN_IMAGE.getValue()) { // generate an image if necessary Trace.line(0, "Generating target image..."); final String[] generatorArgs = {"-trace=1", "-run=" + JTAbstractRunScheme.class.getPackage().getName() + "." + RUNSCHEME_PACKAGE.getValue()}; final String[] systemProperties = {}; final String[] javaArgs = buildJavaArgs(BootImageGenerator.class, appendArgs(systemProperties, GEN_IMAGE_PROPS.getValue()), appendArgs(generatorArgs, GEN_IMAGE_ARGS.getValue())); exec(null, javaArgs, System.out, System.err, System.in); } if (RUN_IMAGE.getValue()) { // generate the run scheme if necessary Trace.line(0, "Running target image..."); final File defaultImagePath = BootImageGenerator.getDefaultVMDirectory(); final String[] imageArgs = {"./maxvm"}; exec(defaultImagePath, appendArgs(imageArgs, RUN_IMAGE_ARGS.getValue()), System.out, System.err, System.in); } } private static String[] appendArgs(String[] args, List<String> extraArgs) { String[] result = args; if (extraArgs.size() > 0) { result = new String[args.length + extraArgs.size()]; System.arraycopy(args, 0, result, 0, args.length); final String[] extraArgsArray = new String[extraArgs.size()]; extraArgs.toArray(extraArgsArray); System.arraycopy(extraArgsArray, 0, result, args.length, extraArgs.size()); } return result; } private static void runExecutor(String alias, String[] args, Registry<JavaExecHarness.Executor> executors) { Trace.line(0, "Beginning tests with " + alias + " executor..."); final Registry<TestHarness> harnesses = new Registry<TestHarness>(TestHarness.class, true); final JavaExecHarness javaExecHarness = new JavaExecHarness(executors.getInstance(alias)); harnesses.registerObject("java", javaExecHarness); final TestEngine engine = new TestEngine(harnesses); engine.setVerboseLevel(VERBOSE.getValue()); engine.setLoadingPackages(LOADING_PACKAGES.getValue()); engine.parseAndRunTests(args, FILTER.getValue()); engine.report(System.out); Trace.line(0); } private static String[] buildJavaArgs(Class javaMainClass, String[] systemProperties, String[] args) { final LinkedList<String> cmd = new LinkedList<String>(); cmd.add("java"); cmd.add("-d64"); cmd.add("-cp"); cmd.add(System.getProperty("java.class.path")); for (int i = 0; i < systemProperties.length; i++) { cmd.add("-D" + systemProperties[i]); } cmd.add(javaMainClass.getName()); for (String arg : args) { cmd.add(arg); } return cmd.toArray(new String[0]); } private static void exec(File workingDir, String[] command, OutputStream out, OutputStream err, InputStream in) throws IOException, InterruptedException { Trace.line(1, "Executing process in directory: " + workingDir); for (String c : command) { Trace.line(1, " " + c); } final Process process = Runtime.getRuntime().exec(command, null, workingDir); try { final Redirector stderr = Streams.redirect(process, process.getErrorStream(), err, command + " [stderr]", 50); final Redirector stdout = Streams.redirect(process, process.getInputStream(), out, command + " [stdout]"); final Redirector stdin = Streams.redirect(process, in, process.getOutputStream(), command + " [stdin]"); final int exitValue = process.waitFor(); stderr.close(); stdout.close(); stdin.close(); if (exitValue != 0) { throw ProgramError.unexpected("execution of command failed: " + command + " [exit code = " + exitValue + "]"); } } finally { process.destroy(); } } }