1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
|
/*
* Copyright (c) 2006, 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 nsk.share.jdi;
import nsk.share.Consts;
import nsk.share.TestBug;
import nsk.share.jpda.AbstractDebuggeeTest;
import java.io.*;
import java.util.*;
/*
* This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM
* SerialExecutionDebugger is used together with SerialExecutionDebuggee, execution process is following:
*
* - SerialExecutionDebugger reads tests to execute from input file, test description is debugger class name and test's parameters,
* if 'shuffle' option is specified in input file debugger executes tests in random order (input file should contain line "OPTIONS:shuffle").
* SerialExecutionDebugger can execute tests several times in loop, number of iterations should be specified in input file in following manner:
* OPTIONS:iterations <iterations_number>.
*
* - SerialExecutionDebugger starts debuggee VM with main class SerialExecutionDebuggee,
* initializes IOPipe and 'debuggee' object which represents debuggee VM
*
* - for each test from input file:
*
* - SerialExecutionDebugger creates object of current debugger and initializes it with already created pipe and debuggee
* - SerialExecutionDebugger sends command to SerialExecutionDebuggee: 'COMMAND_EXECUTE_DEBUGGEE <CurrentDebuggeeName>'
* (CurrentDebuggeeName name should provide current debugger), and waits READY signal from debuggee
* - SerialExecutionDebuggee parses received command, extracts debugee name, creates object of current debuggee, which should be
* subclass of nsk.share.jpda.AbstractDebuggeeTestName
* - SerialExecutionDebuggee executes current debuggee's method 'doTest()', in this method debuggee sends signal READY
* and waits debugger command
* - SerialExecutionDebugger receives signal READY and executes current debugger's method 'doTest()', in
* this method debugger should perform test
* - when debugger method doTest() finishes SerialExecutionDebugger checks is this test passed or failed and
* sends command QUIT to the current debuggee, and when current debuggee finishes sends command 'COMMAND_CLEAR_DEBUGGEE' to the SerialExecutionDebuggee,
* after this command SerialExecutionDebugger and SerialExecutionDebuggee ready to execute next test
*
* - when all tests was executed SerialExecutionDebugger sends command QUIT to the SerialExecutionDebuggee and exits
*
* SerialExecutionDebugger requires "-configFile <ini-file>" parameter, <ini-file> - file with list of tests for execution
*/
public class SerialExecutionDebugger extends TestDebuggerType2 {
static public void main(String[] args) {
System.exit(Consts.JCK_STATUS_BASE + new SerialExecutionDebugger().runIt(args, System.out));
}
public String debuggeeClassName() {
return SerialExecutionDebuggee.class.getName();
}
// contains test's debugger class name and test parameters
static class Test {
public Test(String debuggerClassName, String[] arguments) {
this.debuggerClassName = debuggerClassName;
this.arguments = arguments;
}
public String argumentsToString() {
String result = "";
for (String argument : arguments)
result += argument + " ";
return result;
}
String debuggerClassName;
String arguments[];
}
private Test tests[];
// how many times execute tests
private int iterations = 1;
// requires "-configFile <ini-file>" parameter, <ini-file> - file with list
// of tests for execution
protected String[] doInit(String args[], PrintStream out) {
args = super.doInit(args, out);
String configFileName = null;
ArrayList<String> standardArgs = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-configFile") && (i < args.length - 1)) {
configFileName = args[i + 1];
i++;
} else
standardArgs.add(args[i]);
}
if (configFileName == null) {
throw new TestBug("Config file wasn't specified (use option -configFile <file name>)");
}
tests = parseConfigFile(configFileName);
if (tests.length == 0)
throw new TestBug("Tests to run were not specified");
return standardArgs.toArray(new String[] {});
}
// read test names and test parameters from ini-file
private Test[] parseConfigFile(String fileName) {
List<Test> result = new ArrayList<Test>();
boolean shuffle = false;
try {
File file = new File(fileName);
LineNumberReader lineReader = new LineNumberReader(new FileReader(file));
String line = null;
while ((line = lineReader.readLine()) != null) {
// skip empty lines and comments started with '#"
if (line.length() == 0 || line.startsWith("#"))
continue;
if (line.startsWith("OPTIONS:")) {
String arguments[] = line.substring(8).split(" ");
for (int i = 0; i < arguments.length; i++) {
if (arguments[i].equalsIgnoreCase("shuffle"))
shuffle = true;
else if (arguments[i].equalsIgnoreCase("iterations") && (i < (arguments.length - 1))) {
iterations = Integer.parseInt(arguments[i + 1]);
i++;
}
}
continue;
}
StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line));
tokenizer.resetSyntax();
tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE);
tokenizer.whitespaceChars(' ', ' ');
if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
throw new TestBug("Invalid ini file format");
String testClassName = tokenizer.sval;
List<String> parameters = new ArrayList<String>();
int token;
while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
if (token == StreamTokenizer.TT_WORD) {
if (tokenizer.sval.equals("$CLASSPATH"))
parameters.add(classpath);
else
parameters.add(tokenizer.sval);
}
if (token == StreamTokenizer.TT_NUMBER) {
parameters.add("" + tokenizer.nval);
}
}
result.add(new Test(testClassName, parameters.toArray(new String[] {})));
}
} catch (IOException e) {
throw new TestBug("Exception during config file parsing: " + e);
}
if (shuffle) {
if (testWorkDir == null)
throw new TestBug("Debugger requires -testWorkDir parameter");
Collections.shuffle(result);
// save resulted tests sequence in file (to simplify reproducing)
try {
File file = new File(testWorkDir + File.separator + "run.tests");
file.createNewFile();
PrintWriter writer = new PrintWriter(new FileWriter(file));
for (Test test : result) {
writer.println(test.debuggerClassName + " " + test.argumentsToString());
}
writer.close();
} catch (IOException e) {
throw new TestBug("Unexpected IOException: " + e);
}
}
System.out.println("Tests execution order: ");
for (Test test : result) {
System.out.println(test.debuggerClassName + " " + test.argumentsToString());
}
return result.toArray(new Test[] {});
}
public void doTest() {
stresser.start(iterations);
try {
if (iterations == 1) {
/*
* Since many test couldn't be run in single VM twice and test config specifies only 1 iteration don't
* multiple iterations by iterations factor and execute tests once (not depending on iterations factor)
*/
executeTests();
} else {
while (stresser.continueExecution()) {
if (!executeTests()) {
// if error occured stop execution
break;
}
}
}
} finally {
stresser.finish();
}
}
boolean executeTests() {
// maximum execution time of single test
long maxExecutionTime = 0;
for (Test test : tests) {
long testStartTime = System.currentTimeMillis();
TestDebuggerType2 debugger = null;
try {
// create debugger object
Class debuggerClass = Class.forName(test.debuggerClassName);
if (!TestDebuggerType2.class.isAssignableFrom(debuggerClass)) {
setSuccess(false);
log.complain("Invalid debugger class: " + debuggerClass);
return false;
}
// init test debugger, pass to the debugger already created
// objects: argHandler, log, pipe, debuggee, vm
debugger = (TestDebuggerType2) debuggerClass.newInstance();
debugger.initDebugger(argHandler, log, pipe, debuggee, vm);
debugger.doInit(test.arguments, System.out);
} catch (Exception e) {
setSuccess(false);
log.complain("Unexpected exception during debugger initialization: " + e);
e.printStackTrace(log.getOutStream());
return false;
}
log.display("Execute debugger: " + debugger);
// send command to the SerialExecutionDebuggee (create debuggee
// object)
pipe.println(SerialExecutionDebuggee.COMMAND_EXECUTE_DEBUGGEE + ":" + debugger.debuggeeClassName());
// wait first READY from AbstractDebuggeeTest.doTest() (debuggee
// sends this command when it was initialized and ready for
// test)
if (!isDebuggeeReady())
return false;
try {
// here debuggee should be ready for test and current
// debugger may perform test
debugger.doTest();
if (debugger.getSuccess()) {
log.display("Debugger " + debugger + " finished successfully");
} else {
setSuccess(false);
log.complain("Debugger " + debugger + " finished with errors");
}
} catch (TestBug testBug) {
setSuccess(false);
log.complain("Test bug in " + debugger + ": " + testBug);
testBug.printStackTrace(log.getOutStream());
} catch (Throwable t) {
setSuccess(false);
log.complain("Unexpected exception during test execution(debugger: " + debugger + "): " + t);
t.printStackTrace(log.getOutStream());
}
// send QUIT command to the current debuggee
pipe.println(AbstractDebuggeeTest.COMMAND_QUIT);
if (!isDebuggeeReady())
return false;
// send command to the SerialExecutionDebuggee
pipe.println(SerialExecutionDebuggee.COMMAND_CLEAR_DEBUGGEE);
if (!isDebuggeeReady())
return false;
long testExecutionTime = System.currentTimeMillis() - testStartTime;
if (testExecutionTime > maxExecutionTime)
maxExecutionTime = testExecutionTime;
if (maxExecutionTime > stresser.getTimeLeft()) {
log.display("WARNING: stop test execution because of timeout " +
"(max execution time for single test: " + maxExecutionTime + ", time left: " + stresser.getTimeLeft() + ")");
return false;
}
}
return true;
}
}
|