1 /* 2 * Copyright (c) 2010, 2018, 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 */ 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 */ 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 */ 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 */ 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 = "seed", default_value = "0", description = "Initial random seed") 93 private long _seed; 94 95 @Option(name = "runs", default_value = "1", description = "How many times the test should be re-run") 96 private int runs = 1; 97 98 // Some internal stuff 99 private static MlvmTest instance; 100 101 /** 102 * Sets internal static variable to instance of the test. 103 * Used in debugger/debuggee tests. 104 * Not intended to work if there are several MlvmTests created. 105 * @param inst Instance of the test 106 */ 107 public static void setInstance(MlvmTest inst) { 108 instance = inst; 109 } 110 111 /** 112 * Returns internal static variable holding instance of the test, which was set using {@link #setInstance()}. 113 * Used in debugger/debuggee tests. 114 * Not intended to work if there are several MlvmTests created. 115 * @return Instance of the test 116 */ 117 public static MlvmTest getInstance() { 118 return instance; 119 } 120 121 private static String name = "Test"; 122 123 /** 124 * Sets internal static variable to the name of the test. 125 * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee 126 * Not intended to work if there are several MlvmTests created 127 * @param n Name of the test 128 */ 129 public static void setName(String n) { 130 name = n; 131 } 132 133 /** 134 * Returns internal static variable holding the name of the test. 135 * Debugger/debuggee MLVM tests use this feature to differentiate logging from debugger and debuggee 136 * Not intended to work if there are several MlvmTests created 137 * @return Name of the test 138 */ 139 public static String getName() { 140 return name; 141 } 142 143 void initRNG() { 144 if (_seed != 0) { 145 Env.setRNGSeed(_seed); 146 } 147 Env.traceVerbose("Initial seed = " + _seed); 148 } 149 150 /** 151 * Sets number of test runs 152 * @param r Number of test runs 153 */ 154 public void setRunsNumber(int r) { 155 runs = r; 156 } 157 158 /** 159 * Return number of test runs 160 * @return Number of test runs 161 */ 162 public int getRunsNumber() { 163 return runs; 164 } 165 166 // Sugar... 167 /** 168 * Provides Random Number Generator for the test. The tests should always use this generator 169 * to guarantee repeatability (using -seed option), especially in multi-threaded usages 170 * @return Random number generator for this thread, seeded with command-line option, if provided 171 */ 172 public static Random getRNG() { 173 return Env.getRNG(); 174 } 175 176 /** 177 * Returns logger, which is used in all MLVM framework. This guarantees correct ordering of messages 178 * @return Logger object 179 */ 180 public static Log getLog() { 181 return Env.getLog(); 182 } 183 184 /** 185 * ArgumentParser is the old implementation of command-line parser (the new tests should use 186 * vm.share.options framework). However it is maintained, because nsk JDI/SAJDI framework is built 187 * on ArgumentParser. 188 * @return ArgumentParser object created with command-line options (see {@link MlvmTestExecutor} 189 * for details) 190 */ 191 public static ArgumentParser getArgumentParser() { 192 return Env.getArgParser(); 193 } 194 195 // ...and spice 196 197 /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. 198 * Test fails if exception has not been thrown. 199 * Boolean value returned by {@link run()} method is ignored. 200 * Calling {@link #markTestFailed()} causes test to fail anyway. 201 * <p> 202 * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher 203 * to anticipate the exception instead of the positive (normal) mode. 204 * @param classes The list of exception classes 205 * Empty list or null indicates that test is positive. 206 */ 207 @SafeVarargs 208 public final void setRequiredExceptions(Class<? extends Throwable>... classes) { 209 setRequiredExceptions(Arrays.asList(classes)); 210 } 211 212 /* Makes the test "negative": one of the specified exception classes has to be thrown by the test to pass. 213 * Test fails if exception has not been thrown. 214 * Boolean value returned by {@link run()} method is ignored. 215 * Calling {@link #markTestFailed()} causes test to fail anyway. 216 * <p> 217 * Invoke this method BEFORE run() method (e.g., in prolog) to instruct launcher 218 * @param classes The list of exception classes. 219 * Empty list or null indicates that test is positive (in its standard form) 220 */ 221 public final void setRequiredExceptions(List<Class<? extends Throwable>> classes) { 222 if (requiredExceptionClasses.size() > 0) { 223 Env.traceNormal("Expected exceptions specified in the test are overridden in command-line"); 224 return; 225 } 226 227 requiredExceptionClasses = classes; 228 } 229 230 /** 231 * Returns the list of required exceptions 232 * (please see {@link #setRequiredExceptions(Class<? extends Throwable>... classes)} method for details. 233 * @return The list of exception classes. Empty list or null indicates that test is positive (in its standard form) 234 */ 235 public final List<Class<? extends Throwable>> getRequiredExceptions() { 236 return requiredExceptionClasses; 237 } 238 239 private boolean testMarkedFailed = false; 240 241 /** 242 * Marks the test as failed. 243 * Regardless of run() method return value, the test is considered failed. Operation is not reversible. 244 * Can be called from multiple threads 245 */ 246 protected final void markTestFailed() { 247 markTestFailed(null, null); 248 } 249 250 /** 251 * Marks the test as failed, indicating falure reason. 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 */ 256 protected final void markTestFailed(String msg) { 257 markTestFailedImpl(msg, null); 258 } 259 260 /** 261 * Marks the test as failed, indicating falure reason and exception, which caused it. 262 * Regardless of run() method return value, the test is considered failed. Operation is not reversible. 263 * Can be called from multiple threads 264 * @param msg A message to log (using Log.complain() method) 265 * @param t An exception to log 266 */ 267 protected final void markTestFailed(String msg, Throwable t) { 268 markTestFailedImpl(msg, t); 269 } 270 271 private synchronized void markTestFailedImpl(String msg, Throwable t) { 272 testMarkedFailed = true; 273 274 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 275 Env.complain(t, "%s marked failed at %s%s", getName(), stackTrace[3], 276 msg == null ? "" : ":\n" + msg); 277 278 } 279 280 /** 281 * Checks if the test has marked failed. 282 * @return true, if the test marked failed 283 */ 284 protected final synchronized boolean isMarkedFailed() { 285 return testMarkedFailed; 286 } 287 288 private static boolean dumpHeapAfter = false; 289 290 /** 291 * Checks if heap dump requestd after running the test. 292 * @return true, if the test marked failed 293 * @see MlvmTestExecutor for heap dumping details. 294 */ 295 public static synchronized boolean getHeapDumpAfter() { 296 return dumpHeapAfter; 297 } 298 299 /** 300 * Sets or clears heap dumping request. Heap is dumped in MlvmTestExecutor after running the test. 301 * 302 * NB. heap dumping uses ProcessUtils libraries, so it should be added to library path in cfg-file: 303 * {@code export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${COMMON_LIBS_LOCATION}/lib/${ARCH}/vm/share"} 304 * @param enable true, if heap should be dumped, false if not 305 * @see MlvmTestExecutor for heap dumping details. 306 */ 307 public static synchronized void setHeapDumpAfter(boolean enable) { 308 dumpHeapAfter = enable; 309 } 310 311 protected static Stresser createStresser() { 312 Stresser s = new Stresser(getArgumentParser().getStressOptions()); 313 if (getLog().getTraceLevel() >= TraceLevel.TRACE_VERBOSE) { 314 s.printStressInfo(getLog().getOutStream()); 315 } 316 return s; 317 } 318 319 protected static StressOptions getStressOptions() { 320 return getArgumentParser().getStressOptions(); 321 } 322 323 // Launchers are left here for compatibility. Launching code has been moved to MlvmTestExecutor 324 // TODO: A minor bug has to be filed to replace MlvmTest.launch() calls with MlvmTestExecutor.launch() 325 326 protected static void launch(ArgumentParser argumentParser) { 327 MlvmTestExecutor.launch(argumentParser); 328 } 329 330 protected static void launch(ArgumentParser argumentParser, Object[] constructorArgs) { 331 MlvmTestExecutor.launch(argumentParser, constructorArgs); 332 } 333 334 protected static void launch(String[] args) { 335 MlvmTestExecutor.launch(args, null); 336 } 337 338 protected static void launch(String[] args, Object[] constructorArgs) { 339 MlvmTestExecutor.launch(args, constructorArgs); 340 } 341 342 }