Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmTestExecutor.java
41155 views
1
/*
2
* Copyright (c) 2014, 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.lang.reflect.Constructor;
27
import java.util.List;
28
29
import nsk.share.Consts;
30
import nsk.share.ArgumentParser;
31
import vm.share.ProcessUtils;
32
import vm.share.options.IgnoreUnknownArgumentsHandler;
33
import vm.share.options.OptionSupport;
34
35
/**
36
* This class executes a test based on (a subclass of) either:
37
* <ul>
38
* <li>{@link vm.mlvm.share.MlvmTest}
39
* <li>{@link java.lang.Runnable}
40
* </ul>
41
* using a number of launch() methods.
42
*
43
* Command-line parameters are parsed and set to the instance fields of the test marked with {@literal@}Option/Options annotations. See {@link vm.share.options} framework for details.
44
*
45
* Arguments for test constructor can be passed as well.
46
*
47
* Additionally the launch() methods:
48
* <ul>
49
* <li>measures test run time
50
* <li> handles all test status passing methods (via boolean return value, via MlvmTest.markTestFailed() calls, exception thrown from overriden run() method)
51
* <li>optionally dumps heap after test execution if MlvmTest.setHeapDumpAfer(true) was called
52
* </ul>
53
*
54
* @see vm.mlvm.share.MlvmTest
55
* @see vm.share.options
56
*
57
*/
58
public class MlvmTestExecutor {
59
60
/**
61
* The heap dump file name. If you call MlvmTest.setHeapDumpAfter(true), the heap is dumped into file
62
* specified by this constant when test finishes
63
*/
64
public static final String HEAP_DUMP_FILENAME = "heap.dump";
65
66
/**
67
* Launches MLVM test.
68
* Please see documentation for {@link #launch(Class<?> testClass, Object[] constructorArgs)} method.
69
*
70
* This version of the method is a syntactic shugar to launch test in this way:
71
*
72
* <code>
73
* public class MyTest extends MlvmTest {
74
* ...
75
* public static void main(String[] args) {
76
* MlvmTestExecutor.launch(new YourCustomArgumentParser(args));
77
* }
78
* }
79
* </code>
80
*
81
* @param args Command-line arguments, which are taken from supplied ArgumentParser (ArgumentParser is needed for compatibility with old tests)
82
and set to appropriate test instance fields using vm.share.options framework
83
* @see #launch(Class<?> testClass, Object[] constructorArgs)
84
*/
85
public static void launch(ArgumentParser argumentParser) {
86
launch(argumentParser, null);
87
}
88
89
/**
90
* Launches MLVM test.
91
* Please see documentation for {@link #launch(Class<?> testClass, Object[] constructorArgs)} method.
92
*
93
* This version of the method is a syntactic shugar to launch test in this way:
94
*
95
* <code>
96
* public class MyTest extends MlvmTest {
97
* ...
98
* public static void main(String[] args) {
99
* MlvmTestExecutor.launch(new YourCustomArgumentParser(args), new Object[] { constructor-arguments... });
100
* }
101
* }
102
* </code>
103
*
104
* @param args Command-line arguments, which are taken from supplied ArgumentParser (ArgumentParser is needed for compatibility with old tests)
105
and set to appropriate test instance fields using vm.share.options framework
106
* @param constructorArgs Arguments, which are parsed to test constructor
107
* @see #launch(Class<?> testClass, Object[] constructorArgs)
108
*/
109
public static void launch(ArgumentParser argumentParser, Object[] constructorArgs) {
110
Env.init(argumentParser);
111
launch(constructorArgs);
112
}
113
114
/**
115
* Launches MLVM test.
116
* Please see documentation for {@link #launch(Class<?> testClass, Object[] constructorArgs)} method.
117
*
118
* This version of the method is a syntactic shugar to launch test in this way:
119
*
120
* <code>
121
* public class MyTest extends MlvmTest {
122
* ...
123
* public static void main(String[] args) {
124
* MlvmTestExecutor.launch(args);
125
* }
126
* }
127
* </code>
128
*
129
* @param args Command-line arguments, which are parsed using internal ArgumentParser (for compatibility with old tests) and also set to appropriate test instance fields using vm.share.options framework
130
* @see #launch(Class<?> testClass, Object[] constructorArgs)
131
*/
132
public static void launch(String[] args) {
133
launch(args, null);
134
}
135
136
/**
137
* Launches MLVM test.
138
* Please see documentation for {@link #launch(Class<?> testClass, Object[] constructorArgs)} method.
139
*
140
* This version of the method is a syntactic shugar to launch test in this way:
141
*
142
* <code>
143
* public class MyTest extends MlvmTest {
144
* ...
145
* public static void main(String[] args) {
146
* MlvmTestExecutor.launch(args, new Object[] { constructor-arguments... });
147
* }
148
* }
149
* </code>
150
*
151
* @param args Command-line arguments, which are parsed using internal ArgumentParser (for compatibility with old tests) and also set to appropriate test instance fields using vm.share.options framework
152
* @param constructorArgs Arguments, which are parsed to test constructor
153
* @see #launch(Class<?> testClass, Object[] constructorArgs)
154
*/
155
public static void launch(String[] args, Object[] constructorArgs) {
156
Env.init(args);
157
launch(constructorArgs);
158
}
159
160
/**
161
* Launches MLVM test.
162
* Please see documentation for {@link #launch(Class<?> testClass, Object[] constructorArgs)} method.
163
*
164
* This version of the method is a syntactic shugar to launch test in this way:
165
*
166
* <code>
167
* public class MyTest extends MlvmTest {
168
* ...
169
* void aMethod() {
170
* ...
171
* MlvmTestExecutor.launch(new Object[] { constructor-arguments... });
172
* }
173
* }
174
* </code>
175
*
176
* @param constructorArgs Arguments, which are parsed to test constructor
177
* @see #launch(Class<?> testClass, Object[] constructorArgs)
178
*/
179
public static void launch(Object[] constructorArgs) {
180
Class<?> testClass = getTestClassFromCallerStack();
181
182
if (testClass == null) {
183
throw new RuntimeException("TEST BUG: Can't find an instance of MlvmTest or Runnable in the stacktrace");
184
}
185
186
launch(testClass, constructorArgs);
187
}
188
189
private static Class<?> getTestClassFromCallerStack() {
190
try {
191
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
192
193
// Elements of the stack trace: 0=Thread.getStackTrace(), 1rd=this method, 2nd=launch() method
194
// So we start searching from the most outer frame and finish searching at element 3
195
for (int i = stackTrace.length - 1; i >= 3; --i) {
196
StackTraceElement e = stackTrace[i];
197
Class<?> klass = Class.forName(e.getClassName());
198
if (MlvmTest.class.isAssignableFrom(klass)) {
199
return klass;
200
}
201
}
202
203
return null;
204
} catch (ClassNotFoundException e) {
205
throw new RuntimeException("Unable to get Class object by its name either due to a different ClassLoader (a test bug) or JVM error", e);
206
}
207
}
208
209
/**
210
* Launches MLVM test. The method is the principal MLVM test launcher. This method in conjunction with {@link #runMlvmTest} method:
211
* <ol>
212
* <li>instantiates test class (optionally passing arguments to constructor)
213
* <li>parses command-line arguments using vm.share.options framework and updates the appropriate test fields
214
* <li>launches the tests
215
* <li>handles all test status passing methods (see below)
216
* <li>performs System.exit() with VM-testbase standard exit code 95 (success) or 97 (failure).
217
* </ol>
218
*
219
* <p>The following tests status passing mechanism are available to test writer:
220
* <ol>
221
* <li>Return a boolean value (true if test passed, false otherwise. Good for simple tests)
222
* <li>Assume that test has failed by calling {@link MlvmTest#markTestFailed()} method (suitable for complex logic and multithreaded tests)
223
* <li>by throwing exception from test {@link MlvmTest#run()} method
224
* </ol>
225
226
* <p>Additionally the launcher:
227
* <ul>
228
* <li>measures test run time and logs it
229
* <li>optionally dumps heap after test execution if {@link MlvmTest#setHeapDumpAfer(true)} was called
230
* <li>enables verbose logging on error
231
* </ul>
232
*
233
* @param testClass a class to instantiate. Has to be subclass of vm.mlvm.share.MlvmTest or java.lang.Runnable
234
* @param constructorArgs Arguments to pass to test constructor. Can be null.
235
* @see #runMlvmTest(Class<?> testClass, Object[] constructorArgs)
236
*/
237
public static void launch(Class<?> testClass, Object[] constructorArgs) {
238
Env.getLog().enableVerboseOnError(true);
239
240
long startTime = System.currentTimeMillis();
241
boolean passed;
242
try {
243
Env.traceDebug(MlvmTest.getName() + " class: " + testClass);
244
passed = runMlvmTest(testClass, constructorArgs);
245
} catch (Throwable e) {
246
Env.complain(e, MlvmTest.getName() + " caught an exception: ");
247
passed = false;
248
}
249
250
long finishTime = System.currentTimeMillis();
251
Env.traceNormal("The test took " + (finishTime - startTime) + " ms");
252
253
optionallyDumpHeap();
254
255
final String testNameUC = MlvmTest.getName().toUpperCase();
256
if (passed) {
257
Env.display(testNameUC + " PASSED");
258
System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);
259
} else {
260
Env.display(testNameUC + " FAILED");
261
System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
262
}
263
}
264
265
private static void optionallyDumpHeap() {
266
try {
267
if (MlvmTest.getHeapDumpAfter()) {
268
ProcessUtils.dumpHeapWithHotspotDiagnosticMXBean(HEAP_DUMP_FILENAME);
269
}
270
} catch (Exception e) {
271
Env.traceNormal(e, "Error dumping heap: ");
272
}
273
}
274
275
/**
276
* Launches MLVM test (syntatic shugar method).
277
* Calls {@link #runMlvmTest(Class<?> testClass, Object[] constructorArgs)} method providing no arguments to pass to the test constructor.
278
*
279
* The method throws unchecked exception when there is an error in test logic or handling.
280
* Exceptions thrown from MlvmTest.run() method or test constructor are wrapped into java.lang.RuntimeException or java.lang.Error
281
*
282
* @param testClass a class to instantiate. Has to be subclass of vm.mlvm.share.MlvmTest or java.lang.Runnable
283
* @return true if test passed, false otherwise
284
* @see #runMlvmTest(Class<?> testClass, Object[] constructorArgs)
285
*/
286
public static boolean runMlvmTest(Class<?> testClass) {
287
return runMlvmTest(testClass, null);
288
}
289
290
/**
291
* Launches MLVM test. In details, it:
292
* <ol>
293
* <li>instantiates test class (optionally passing arguments to constructor)
294
* <li>parses command-line arguments using vm.share.options framework and updates the appropriate test fields
295
* <li>launches the tests
296
* <li>handles all test status passing methods (see below)
297
* </ol>
298
*
299
* <p>Unlike {@link #launch()} methods, it does NOT:
300
* <ul>
301
* <li>performs System.exit() with VM-testbase standard exit code 95 (success) or 97 (failure).
302
* <li>measures test run time and logs it
303
* <li>optionally dumps heap after test execution if {@link MlvmTest#setHeapDumpAfer(true)} was called
304
* <li>enables verbose logging on error
305
* </ul>
306
* Please see {@link #launch(Class<?> testClass, Object[] constructorArgs)} for additional details.
307
*
308
* The method throws unchecked exception when there is an error in test logic or handling.
309
* Exceptions thrown from MlvmTest.run() method or test constructor are wrapped into java.lang.RuntimeException or java.lang.Error
310
*
311
* @param testClass a class to instantiate. Has to be subclass of vm.mlvm.share.MlvmTest or java.lang.Runnable
312
* @param constructorArgs Arguments to pass to test constructor. Can be null.
313
* @return true if test passed, false otherwise
314
* @see #launch(Class<?> testClass, Object[] constructorArgs)
315
*/
316
public static boolean runMlvmTest(Class<?> testClass, Object[] constructorArgs) {
317
boolean passed;
318
Throwable exception = null;
319
320
try {
321
MlvmTest instance = constructMlvmTest(testClass, constructorArgs);
322
setupMlvmTest(instance);
323
324
instance.initializeTest();
325
326
try {
327
passed = runMlvmTestInstance(instance);
328
} catch(Throwable e) {
329
exception = e;
330
passed = false;
331
}
332
333
try {
334
instance.finalizeTest(passed);
335
} catch (Throwable e) {
336
Env.complain(e, "TEST BUG: exception thrown in finalizeTest");
337
if (exception == null) {
338
exception = e;
339
}
340
passed = false;
341
}
342
343
} catch (Throwable e) {
344
Env.complain(e, "TEST BUG: exception thrown when instantiating/preparing test for run");
345
exception = e;
346
passed = false; // never really needed, but let's keep it
347
}
348
349
if (exception != null) {
350
Env.throwAsUncheckedException(exception); // always throws
351
}
352
353
return passed;
354
}
355
356
private static void setupMlvmTest(MlvmTest instance) {
357
MlvmTest.setInstance(instance);
358
OptionSupport.setup(instance, Env.getArgParser().getRawArguments(), new IgnoreUnknownArgumentsHandler());
359
}
360
361
private static boolean runMlvmTestInstance(MlvmTest instance) throws Throwable {
362
List<Class<? extends Throwable>> expectedExceptions = instance.getRequiredExceptions();
363
int runsCount = instance.getRunsNumber() * instance.getStressOptions().getRunsFactor();
364
if (runsCount < 1) {
365
throw new RuntimeException("Runs number obtained via command-line options is less than 1");
366
}
367
368
int failedRuns = 0;
369
370
try {
371
for (int run = 1; run <= runsCount; ++run) {
372
if (runsCount > 1) {
373
Env.traceNormal("TEST RUN " + run + "/" + runsCount + "; Failed " + failedRuns + " runs");
374
}
375
376
if (run > 1) {
377
instance.resetTest();
378
}
379
380
boolean instancePassed;
381
if (expectedExceptions.size() == 0) {
382
instancePassed = instance.run();
383
} else {
384
try {
385
instance.run();
386
Env.complain("Expected exceptions: " + expectedExceptions + ", but caught none");
387
instancePassed = false;
388
} catch (Throwable e) {
389
if (checkExpectedException(expectedExceptions, e)) {
390
instancePassed = true;
391
} else {
392
Env.complain(e, "Expected exceptions: " + expectedExceptions + ", but caught: ");
393
instancePassed = false;
394
}
395
}
396
}
397
398
if (instance.isMarkedFailed()) {
399
instancePassed = false;
400
}
401
402
if (!instancePassed) {
403
++failedRuns;
404
}
405
}
406
} finally {
407
if (failedRuns > 0) {
408
Env.complain("Failed runs: " + failedRuns + " of " + runsCount);
409
}
410
}
411
412
return failedRuns == 0;
413
}
414
415
private static Object constructTest(Class<?> testClass, Object[] constructorArgs) throws Throwable {
416
if (constructorArgs == null || constructorArgs.length == 0) {
417
return testClass.newInstance();
418
}
419
420
for (Constructor<?> c : testClass.getConstructors()) {
421
Class<?> paramClasses[] = c.getParameterTypes();
422
if (!parametersAreAssignableFrom(paramClasses, constructorArgs)) {
423
continue;
424
}
425
426
return c.newInstance(constructorArgs);
427
}
428
429
throw new RuntimeException("Test bug: in class " + testClass.getName() + " no appropriate constructor found for arguments " + constructorArgs);
430
}
431
432
private static MlvmTest constructMlvmTest(Class<?> testClass, Object[] constructorArgs) throws Throwable {
433
Object testObj = constructTest(testClass, constructorArgs);
434
435
MlvmTest instance;
436
if (testObj instanceof MlvmTest) {
437
instance = (MlvmTest) testObj;
438
} else if (testObj instanceof Runnable) {
439
instance = new RunnableWrapper((Runnable) testObj);
440
} else {
441
// You can add wrapping of other types of tests here into MlvmTest if you need
442
throw new RuntimeException("TEST BUG: Test class should be subclass of MlvmTest or Runnable. Its type is "
443
+ testObj.getClass().getName());
444
}
445
446
return instance;
447
}
448
449
private static boolean parametersAreAssignableFrom(Class<?>[] paramClasses, Object[] constructorArgs) {
450
if (paramClasses.length != constructorArgs.length) {
451
return false;
452
}
453
454
for (int i = 0; i < paramClasses.length; ++i) {
455
if (!paramClasses[i].isAssignableFrom(constructorArgs[i].getClass())) {
456
return false;
457
}
458
}
459
460
return true;
461
}
462
463
private static boolean checkExpectedException(List<Class<? extends Throwable>> expectedExceptions, Throwable caught) throws Throwable {
464
for (Class<? extends Throwable> expected : expectedExceptions) {
465
if (expected.isAssignableFrom(caught.getClass())) {
466
Env.traceNormal("Caught anticipated exception " + caught.getClass().getName() + ". Cause: " + caught.getCause());
467
return true;
468
}
469
}
470
471
return false;
472
}
473
474
private static class RunnableWrapper extends MlvmTest {
475
private Runnable runnable;
476
477
public RunnableWrapper(Runnable r) {
478
runnable = r;
479
}
480
481
@Override
482
public boolean run() throws Throwable {
483
runnable.run();
484
return true;
485
}
486
}
487
}
488
489