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