1 /* 2 * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package vm.mlvm.share; 25 26 import java.util.Random; 27 import java.util.concurrent.atomic.AtomicBoolean; 28 import java.util.List; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 32 import nsk.share.ArgumentParser; 33 import nsk.share.Log; 34 import nsk.share.Log.TraceLevel; 35 import nsk.share.test.StressOptions; 36 import nsk.share.test.Stresser; 37 import vm.share.options.Option; 38 import vm.mlvm.share.ExceptionsOptionObjectFactory; 39 40 /** 41 * The base class for MLVM tests. 42 * Subclasses need to override {@link #run()} method to implement test logic. 43 */ 44 public abstract class MlvmTest { 45 46 /** 47 * MLVM tests are expected to implement this method to provide the logic. 48 * 49 * @return true if test passed, false if failed 50 * @throws Throwable any subclass of Throwable to indicate test failure 51 */ run()52 public abstract boolean run() throws Throwable; 53 54 /** Performs pre-run (prolog) actions in MlvmTest subclasses. 55 * The default implementation does nothing. 56 * Sublcasses may override this method to perform custom actions after test is initialized 57 * (initialization order is described in MlvmTestExecutor class) but before {@link run()} method is invoked. 58 * @throws Throwable in case of problem, which is interpreted as a test failure 59 * @see MlvmTestExecutor 60 */ initializeTest()61 protected void initializeTest() throws Throwable { 62 } 63 64 /** Performs post-run (epilog) actions. 65 * This method is executed after the {@link #run()} method. 66 * Does nothing by default. 67 * Subclasses may override this method when some finalization actions are required. 68 * Test fails if this method throws exception. 69 * @param result test execution status: true, if test passed, false otherwise 70 * @throws Throwable may throw any subclass of Throwable to indicate test failure (regardless of run() method result) 71 * @see MlvmTestExecutor 72 */ finalizeTest(boolean result)73 protected void finalizeTest(boolean result) throws Throwable { 74 } 75 76 /** 77 * Resets the tests between runs. 78 * You may override this method, especially if your test supports -stressRunsFactor option 79 * @throws Throwable may throw any subclass of Throwable to indicate test failure (regardless of run() method result) 80 * @see MlvmTestExecutor 81 */ resetTest()82 protected void resetTest() throws Throwable { 83 testMarkedFailed = false; 84 } 85 86 // Options for all MlvmTests 87 @Option(name = "requireExceptions", default_value = "", factory = ExceptionsOptionObjectFactory.class, 88 description = "Specifying this option turns test into negative one: " 89 + "the specified exception class names separated with commas have to be caught for the test to pass") 90 private List<Class<? extends Throwable>> requiredExceptionClasses = new ArrayList<>(); 91 92 @Option(name = "runs", default_value = "1", description = "How many times the test should be re-run") 93 private int runs = 1; 94 95 // Some internal stuff 96 private static MlvmTest instance; 97 98 /** 99 * Sets internal static variable to instance of the test. 100 * Used in debugger/debuggee tests. 101 * Not intended to work if there are several MlvmTests created. 102 * @param inst Instance of the test 103 */ setInstance(MlvmTest inst)104 public static void setInstance(MlvmTest inst) { 105 instance = inst; 106 } 107 108 /** 109 * Returns internal static variable holding instance of the test, which was set using {@link #setInstance()}. 110 * Used in debugger/debuggee tests. 111 * Not intended to work if there are several MlvmTests created. 112 * @return Instance of the test 113 */ getInstance()114 public static MlvmTest getInstance() { 115 return instance; 116 } 117 118 private static String name = "Test"; 119 120 /** 121 * Sets internal static variable to the name of the test. 122 * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee 123 * Not intended to work if there are several MlvmTests created 124 * @param n Name of the test 125 */ setName(String n)126 public static void setName(String n) { 127 name = n; 128 } 129 130 /** 131 * Returns internal static variable holding the name of the test. 132 * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee 133 * Not intended to work if there are several MlvmTests created 134 * @return Name of the test 135 */ getName()136 public static String getName() { 137 return name; 138 } 139 140 /** 141 * Sets number of test runs 142 * @param r Number of test runs 143 */ setRunsNumber(int r)144 public void setRunsNumber(int r) { 145 runs = r; 146 } 147 148 /** 149 * Return number of test runs 150 * @return Number of test runs 151 */ getRunsNumber()152 public int getRunsNumber() { 153 return runs; 154 } 155 156 // Sugar... 157 /** 158 * Provides Random Number Generator for the test. The tests should always use this generator 159 * to guarantee repeatability, especially in multi-threaded usages 160 * @return Random number generator for this thread, seeded with command-line option, if provided 161 */ getRNG()162 public static Random getRNG() { 163 return Env.getRNG(); 164 } 165 166 /** 167 * Returns logger, which is used in all MLVM framework. This guarantees correct ordering of messages 168 * @return Logger object 169 */ getLog()170 public static Log getLog() { 171 return Env.getLog(); 172 } 173 174 /** 175 * ArgumentParser is the old implementation of command-line parser (the new tests should use 176 * vm.share.options framework). However it is maintained, because nsk JDI/SAJDI framework is built 177 * on ArgumentParser. 178 * @return ArgumentParser object created with command-line options (see {@link MlvmTestExecutor} 179 * for details) 180 */ getArgumentParser()181 public static ArgumentParser getArgumentParser() { 182 return Env.getArgParser(); 183 } 184 185 // ...and spice 186 187 /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. 188 * Test fails if exception has not been thrown. 189 * Boolean value returned by {@link run()} method is ignored. 190 * Calling {@link #markTestFailed()} causes test to fail anyway. 191 * <p> 192 * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher 193 * to anticipate the exception instead of the positive (normal) mode. 194 * @param classes The list of exception classes 195 * Empty list or null indicates that test is positive. 196 */ 197 @SafeVarargs setRequiredExceptions(Class<? extends Throwable>.... classes)198 public final void setRequiredExceptions(Class<? extends Throwable>... classes) { 199 setRequiredExceptions(Arrays.asList(classes)); 200 } 201 202 /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. 203 * Test fails if exception has not been thrown. 204 * Boolean value returned by {@link run()} method is ignored. 205 * Calling {@link #markTestFailed()} causes test to fail anyway. 206 * <p> 207 * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher 208 * @param classes The list of exception classes. 209 * Empty list or null indicates that test is positive (in its standard form) 210 */ setRequiredExceptions(List<Class<? extends Throwable>> classes)211 public final void setRequiredExceptions(List<Class<? extends Throwable>> classes) { 212 if (requiredExceptionClasses.size() > 0) { 213 Env.traceNormal("Expected exceptions specified in the test are overridden in command-line"); 214 return; 215 } 216 217 requiredExceptionClasses = classes; 218 } 219 220 /** 221 * Returns the list of required exceptions 222 * (please see {@link #setRequiredExceptions(Class<? extends Throwable>... classes)} method for details. 223 * @return The list of exception classes. Empty list or null indicates that test is positive (in its standard form) 224 */ getRequiredExceptions()225 public final List<Class<? extends Throwable>> getRequiredExceptions() { 226 return requiredExceptionClasses; 227 } 228 229 private boolean testMarkedFailed = false; 230 231 /** 232 * Marks the test as failed. 233 * Regardless of run() method return value, the test is considered failed. Operation is not reversible. 234 * Can be called from multiple threads 235 */ markTestFailed()236 protected final void markTestFailed() { 237 markTestFailed(null, null); 238 } 239 240 /** 241 * Marks the test as failed, indicating falure reason. 242 * Regardless of run() method return value, the test is considered failed. Operation is not reversible. 243 * Can be called from multiple threads 244 * @param msg A message to log (using Log.complain() method) 245 */ markTestFailed(String msg)246 protected final void markTestFailed(String msg) { 247 markTestFailedImpl(msg, null); 248 } 249 250 /** 251 * Marks the test as failed, indicating falure reason and exception, which caused it. 252 * Regardless of run() method return value, the test is considered failed. Operation is not reversible. 253 * Can be called from multiple threads 254 * @param msg A message to log (using Log.complain() method) 255 * @param t An exception to log 256 */ markTestFailed(String msg, Throwable t)257 protected final void markTestFailed(String msg, Throwable t) { 258 markTestFailedImpl(msg, t); 259 } 260 markTestFailedImpl(String msg, Throwable t)261 private synchronized void markTestFailedImpl(String msg, Throwable t) { 262 testMarkedFailed = true; 263 264 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 265 Env.complain(t, "%s marked failed at %s%s", getName(), stackTrace[3], 266 msg == null ? "" : ":\n" + msg); 267 268 } 269 270 /** 271 * Checks if the test has marked failed. 272 * @return true, if the test marked failed 273 */ isMarkedFailed()274 protected final synchronized boolean isMarkedFailed() { 275 return testMarkedFailed; 276 } 277 278 private static boolean dumpHeapAfter = false; 279 280 /** 281 * Checks if heap dump requestd after running the test. 282 * @return true, if the test marked failed 283 * @see MlvmTestExecutor for heap dumping details. 284 */ getHeapDumpAfter()285 public static synchronized boolean getHeapDumpAfter() { 286 return dumpHeapAfter; 287 } 288 289 /** 290 * Sets or clears heap dumping request. Heap is dumped in MlvmTestExecutor after running the test. 291 * 292 * NB. heap dumping uses ProcessUtils libraries, so it should be added to library path in cfg-file: 293 * {@code export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${COMMON_LIBS_LOCATION}/lib/${ARCH}/vm/share"} 294 * @param enable true, if heap should be dumped, false if not 295 * @see MlvmTestExecutor for heap dumping details. 296 */ setHeapDumpAfter(boolean enable)297 public static synchronized void setHeapDumpAfter(boolean enable) { 298 dumpHeapAfter = enable; 299 } 300 createStresser()301 protected static Stresser createStresser() { 302 Stresser s = new Stresser(getArgumentParser().getStressOptions()); 303 if (getLog().getTraceLevel() >= TraceLevel.TRACE_VERBOSE) { 304 s.printStressInfo(getLog().getOutStream()); 305 } 306 return s; 307 } 308 getStressOptions()309 protected static StressOptions getStressOptions() { 310 return getArgumentParser().getStressOptions(); 311 } 312 313 // Launchers are left here for compatibility. Launching code has been moved to MlvmTestExecutor 314 // TODO: A minor bug has to be filed to replace MlvmTest.launch() calls with MlvmTestExecutor.launch() 315 launch(ArgumentParser argumentParser)316 protected static void launch(ArgumentParser argumentParser) { 317 MlvmTestExecutor.launch(argumentParser); 318 } 319 launch(ArgumentParser argumentParser, Object[] constructorArgs)320 protected static void launch(ArgumentParser argumentParser, Object[] constructorArgs) { 321 MlvmTestExecutor.launch(argumentParser, constructorArgs); 322 } 323 launch(String[] args)324 protected static void launch(String[] args) { 325 MlvmTestExecutor.launch(args, null); 326 } 327 launch(String[] args, Object[] constructorArgs)328 protected static void launch(String[] args, Object[] constructorArgs) { 329 MlvmTestExecutor.launch(args, constructorArgs); 330 } 331 332 } 333