| /* |
| * Copyright (c) 2010, 2018, 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 vm.mlvm.share; |
| |
| import java.util.Random; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| |
| import nsk.share.ArgumentParser; |
| import nsk.share.Log; |
| import nsk.share.Log.TraceLevel; |
| import nsk.share.test.StressOptions; |
| import nsk.share.test.Stresser; |
| import vm.share.options.Option; |
| import vm.mlvm.share.ExceptionsOptionObjectFactory; |
| |
| /** |
| * The base class for MLVM tests. |
| * Subclasses need to override {@link #run()} method to implement test logic. |
| */ |
| public abstract class MlvmTest { |
| |
| /** |
| * MLVM tests are expected to implement this method to provide the logic. |
| * |
| * @return true if test passed, false if failed |
| * @throws Throwable any subclass of Throwable to indicate test failure |
| */ |
| public abstract boolean run() throws Throwable; |
| |
| /** Performs pre-run (prolog) actions in MlvmTest subclasses. |
| * The default implementation does nothing. |
| * Sublcasses may override this method to perform custom actions after test is initialized |
| * (initialization order is described in MlvmTestExecutor class) but before {@link run()} method is invoked. |
| * @throws Throwable in case of problem, which is interpreted as a test failure |
| * @see MlvmTestExecutor |
| */ |
| protected void initializeTest() throws Throwable { |
| } |
| |
| /** Performs post-run (epilog) actions. |
| * This method is executed after the {@link #run()} method. |
| * Does nothing by default. |
| * Subclasses may override this method when some finalization actions are required. |
| * Test fails if this method throws exception. |
| * @param result test execution status: true, if test passed, false otherwise |
| * @throws Throwable may throw any subclass of Throwable to indicate test failure (regardless of run() method result) |
| * @see MlvmTestExecutor |
| */ |
| protected void finalizeTest(boolean result) throws Throwable { |
| } |
| |
| /** |
| * Resets the tests between runs. |
| * You may override this method, especially if your test supports -stressRunsFactor option |
| * @throws Throwable may throw any subclass of Throwable to indicate test failure (regardless of run() method result) |
| * @see MlvmTestExecutor |
| */ |
| protected void resetTest() throws Throwable { |
| testMarkedFailed = false; |
| } |
| |
| // Options for all MlvmTests |
| @Option(name = "requireExceptions", default_value = "", factory = ExceptionsOptionObjectFactory.class, |
| description = "Specifying this option turns test into negative one: " |
| + "the specified exception class names separated with commas have to be caught for the test to pass") |
| private List<Class<? extends Throwable>> requiredExceptionClasses = new ArrayList<>(); |
| |
| @Option(name = "seed", default_value = "0", description = "Initial random seed") |
| private long _seed; |
| |
| @Option(name = "runs", default_value = "1", description = "How many times the test should be re-run") |
| private int runs = 1; |
| |
| // Some internal stuff |
| private static MlvmTest instance; |
| |
| /** |
| * Sets internal static variable to instance of the test. |
| * Used in debugger/debuggee tests. |
| * Not intended to work if there are several MlvmTests created. |
| * @param inst Instance of the test |
| */ |
| public static void setInstance(MlvmTest inst) { |
| instance = inst; |
| } |
| |
| /** |
| * Returns internal static variable holding instance of the test, which was set using {@link #setInstance()}. |
| * Used in debugger/debuggee tests. |
| * Not intended to work if there are several MlvmTests created. |
| * @return Instance of the test |
| */ |
| public static MlvmTest getInstance() { |
| return instance; |
| } |
| |
| private static String name = "Test"; |
| |
| /** |
| * Sets internal static variable to the name of the test. |
| * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee |
| * Not intended to work if there are several MlvmTests created |
| * @param n Name of the test |
| */ |
| public static void setName(String n) { |
| name = n; |
| } |
| |
| /** |
| * Returns internal static variable holding the name of the test. |
| * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee |
| * Not intended to work if there are several MlvmTests created |
| * @return Name of the test |
| */ |
| public static String getName() { |
| return name; |
| } |
| |
| void initRNG() { |
| if (_seed != 0) { |
| Env.setRNGSeed(_seed); |
| } |
| Env.traceVerbose("Initial seed = " + _seed); |
| } |
| |
| /** |
| * Sets number of test runs |
| * @param r Number of test runs |
| */ |
| public void setRunsNumber(int r) { |
| runs = r; |
| } |
| |
| /** |
| * Return number of test runs |
| * @return Number of test runs |
| */ |
| public int getRunsNumber() { |
| return runs; |
| } |
| |
| // Sugar... |
| /** |
| * Provides Random Number Generator for the test. The tests should always use this generator |
| * to guarantee repeatability (using -seed option), especially in multi-threaded usages |
| * @return Random number generator for this thread, seeded with command-line option, if provided |
| */ |
| public static Random getRNG() { |
| return Env.getRNG(); |
| } |
| |
| /** |
| * Returns logger, which is used in all MLVM framework. This guarantees correct ordering of messages |
| * @return Logger object |
| */ |
| public static Log getLog() { |
| return Env.getLog(); |
| } |
| |
| /** |
| * ArgumentParser is the old implementation of command-line parser (the new tests should use |
| * vm.share.options framework). However it is maintained, because nsk JDI/SAJDI framework is built |
| * on ArgumentParser. |
| * @return ArgumentParser object created with command-line options (see {@link MlvmTestExecutor} |
| * for details) |
| */ |
| public static ArgumentParser getArgumentParser() { |
| return Env.getArgParser(); |
| } |
| |
| // ...and spice |
| |
| /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. |
| * Test fails if exception has not been thrown. |
| * Boolean value returned by {@link run()} method is ignored. |
| * Calling {@link #markTestFailed()} causes test to fail anyway. |
| * <p> |
| * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher |
| * to anticipate the exception instead of the positive (normal) mode. |
| * @param classes The list of exception classes |
| * Empty list or null indicates that test is positive. |
| */ |
| @SafeVarargs |
| public final void setRequiredExceptions(Class<? extends Throwable>... classes) { |
| setRequiredExceptions(Arrays.asList(classes)); |
| } |
| |
| /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. |
| * Test fails if exception has not been thrown. |
| * Boolean value returned by {@link run()} method is ignored. |
| * Calling {@link #markTestFailed()} causes test to fail anyway. |
| * <p> |
| * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher |
| * @param classes The list of exception classes. |
| * Empty list or null indicates that test is positive (in its standard form) |
| */ |
| public final void setRequiredExceptions(List<Class<? extends Throwable>> classes) { |
| if (requiredExceptionClasses.size() > 0) { |
| Env.traceNormal("Expected exceptions specified in the test are overridden in command-line"); |
| return; |
| } |
| |
| requiredExceptionClasses = classes; |
| } |
| |
| /** |
| * Returns the list of required exceptions |
| * (please see {@link #setRequiredExceptions(Class<? extends Throwable>... classes)} method for details. |
| * @return The list of exception classes. Empty list or null indicates that test is positive (in its standard form) |
| */ |
| public final List<Class<? extends Throwable>> getRequiredExceptions() { |
| return requiredExceptionClasses; |
| } |
| |
| private boolean testMarkedFailed = false; |
| |
| /** |
| * Marks the test as failed. |
| * Regardless of run() method return value, the test is considered failed. Operation is not reversible. |
| * Can be called from multiple threads |
| */ |
| protected final void markTestFailed() { |
| markTestFailed(null, null); |
| } |
| |
| /** |
| * Marks the test as failed, indicating falure reason. |
| * Regardless of run() method return value, the test is considered failed. Operation is not reversible. |
| * Can be called from multiple threads |
| * @param msg A message to log (using Log.complain() method) |
| */ |
| protected final void markTestFailed(String msg) { |
| markTestFailedImpl(msg, null); |
| } |
| |
| /** |
| * Marks the test as failed, indicating falure reason and exception, which caused it. |
| * Regardless of run() method return value, the test is considered failed. Operation is not reversible. |
| * Can be called from multiple threads |
| * @param msg A message to log (using Log.complain() method) |
| * @param t An exception to log |
| */ |
| protected final void markTestFailed(String msg, Throwable t) { |
| markTestFailedImpl(msg, t); |
| } |
| |
| private synchronized void markTestFailedImpl(String msg, Throwable t) { |
| testMarkedFailed = true; |
| |
| StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); |
| Env.complain(t, "%s marked failed at %s%s", getName(), stackTrace[3], |
| msg == null ? "" : ":\n" + msg); |
| |
| } |
| |
| /** |
| * Checks if the test has marked failed. |
| * @return true, if the test marked failed |
| */ |
| protected final synchronized boolean isMarkedFailed() { |
| return testMarkedFailed; |
| } |
| |
| private static boolean dumpHeapAfter = false; |
| |
| /** |
| * Checks if heap dump requestd after running the test. |
| * @return true, if the test marked failed |
| * @see MlvmTestExecutor for heap dumping details. |
| */ |
| public static synchronized boolean getHeapDumpAfter() { |
| return dumpHeapAfter; |
| } |
| |
| /** |
| * Sets or clears heap dumping request. Heap is dumped in MlvmTestExecutor after running the test. |
| * |
| * NB. heap dumping uses ProcessUtils libraries, so it should be added to library path in cfg-file: |
| * {@code export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${COMMON_LIBS_LOCATION}/lib/${ARCH}/vm/share"} |
| * @param enable true, if heap should be dumped, false if not |
| * @see MlvmTestExecutor for heap dumping details. |
| */ |
| public static synchronized void setHeapDumpAfter(boolean enable) { |
| dumpHeapAfter = enable; |
| } |
| |
| protected static Stresser createStresser() { |
| Stresser s = new Stresser(getArgumentParser().getStressOptions()); |
| if (getLog().getTraceLevel() >= TraceLevel.TRACE_VERBOSE) { |
| s.printStressInfo(getLog().getOutStream()); |
| } |
| return s; |
| } |
| |
| protected static StressOptions getStressOptions() { |
| return getArgumentParser().getStressOptions(); |
| } |
| |
| // Launchers are left here for compatibility. Launching code has been moved to MlvmTestExecutor |
| // TODO: A minor bug has to be filed to replace MlvmTest.launch() calls with MlvmTestExecutor.launch() |
| |
| protected static void launch(ArgumentParser argumentParser) { |
| MlvmTestExecutor.launch(argumentParser); |
| } |
| |
| protected static void launch(ArgumentParser argumentParser, Object[] constructorArgs) { |
| MlvmTestExecutor.launch(argumentParser, constructorArgs); |
| } |
| |
| protected static void launch(String[] args) { |
| MlvmTestExecutor.launch(args, null); |
| } |
| |
| protected static void launch(String[] args, Object[] constructorArgs) { |
| MlvmTestExecutor.launch(args, constructorArgs); |
| } |
| |
| } |