Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java
41161 views
/*1* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package nsk.share.jdi;2324import nsk.share.Consts;25import nsk.share.TestBug;26import nsk.share.jpda.AbstractDebuggeeTest;27import java.io.*;28import java.util.*;29import jdk.test.lib.Utils;3031/*32* This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM33* SerialExecutionDebugger is used together with SerialExecutionDebuggee, execution process is following:34*35* - SerialExecutionDebugger reads tests to execute from input file, test description is debugger class name and test's parameters,36* if 'shuffle' option is specified in input file debugger executes tests in random order (input file should contain line "OPTIONS:shuffle").37* SerialExecutionDebugger can execute tests several times in loop, number of iterations should be specified in input file in following manner:38* OPTIONS:iterations <iterations_number>.39*40* - SerialExecutionDebugger starts debuggee VM with main class SerialExecutionDebuggee,41* initializes IOPipe and 'debuggee' object which represents debuggee VM42*43* - for each test from input file:44*45* - SerialExecutionDebugger creates object of current debugger and initializes it with already created pipe and debuggee46* - SerialExecutionDebugger sends command to SerialExecutionDebuggee: 'COMMAND_EXECUTE_DEBUGGEE <CurrentDebuggeeName>'47* (CurrentDebuggeeName name should provide current debugger), and waits READY signal from debuggee48* - SerialExecutionDebuggee parses received command, extracts debugee name, creates object of current debuggee, which should be49* subclass of nsk.share.jpda.AbstractDebuggeeTestName50* - SerialExecutionDebuggee executes current debuggee's method 'doTest()', in this method debuggee sends signal READY51* and waits debugger command52* - SerialExecutionDebugger receives signal READY and executes current debugger's method 'doTest()', in53* this method debugger should perform test54* - when debugger method doTest() finishes SerialExecutionDebugger checks is this test passed or failed and55* sends command QUIT to the current debuggee, and when current debuggee finishes sends command 'COMMAND_CLEAR_DEBUGGEE' to the SerialExecutionDebuggee,56* after this command SerialExecutionDebugger and SerialExecutionDebuggee ready to execute next test57*58* - when all tests was executed SerialExecutionDebugger sends command QUIT to the SerialExecutionDebuggee and exits59*60* SerialExecutionDebugger requires "-configFile <ini-file>" parameter, <ini-file> - file with list of tests for execution61*/62public class SerialExecutionDebugger extends TestDebuggerType2 {63static public void main(String[] args) {64System.exit(Consts.JCK_STATUS_BASE + new SerialExecutionDebugger().runIt(args, System.out));65}6667public String debuggeeClassName() {68return SerialExecutionDebuggee.class.getName();69}7071// contains test's debugger class name and test parameters72static class Test {73public Test(String debuggerClassName, String[] arguments) {74this.debuggerClassName = debuggerClassName;75this.arguments = arguments;76}7778public String argumentsToString() {79String result = "";8081for (String argument : arguments)82result += argument + " ";8384return result;85}8687String debuggerClassName;8889String arguments[];90}9192private Test tests[];9394// how many times execute tests95private int iterations = 1;9697// requires "-configFile <ini-file>" parameter, <ini-file> - file with list98// of tests for execution99protected String[] doInit(String args[], PrintStream out) {100args = super.doInit(args, out);101102String configFileName = null;103104ArrayList<String> standardArgs = new ArrayList<String>();105106for (int i = 0; i < args.length; i++) {107if (args[i].equals("-configFile") && (i < args.length - 1)) {108configFileName = args[i + 1];109i++;110} else111standardArgs.add(args[i]);112}113114if (configFileName == null) {115throw new TestBug("Config file wasn't specified (use option -configFile <file name>)");116}117118tests = parseConfigFile(configFileName);119120if (tests.length == 0)121throw new TestBug("Tests to run were not specified");122123return standardArgs.toArray(new String[] {});124}125126// read test names and test parameters from ini-file127private Test[] parseConfigFile(String fileName) {128List<Test> result = new ArrayList<Test>();129130boolean shuffle = false;131132try {133File file = new File(fileName);134135LineNumberReader lineReader = new LineNumberReader(new FileReader(file));136137String line = null;138139while ((line = lineReader.readLine()) != null) {140// skip empty lines and comments started with '#"141if (line.length() == 0 || line.startsWith("#"))142continue;143144if (line.startsWith("OPTIONS:")) {145String arguments[] = line.substring(8).split(" ");146147for (int i = 0; i < arguments.length; i++) {148if (arguments[i].equalsIgnoreCase("shuffle"))149shuffle = true;150else if (arguments[i].equalsIgnoreCase("iterations") && (i < (arguments.length - 1))) {151iterations = Integer.parseInt(arguments[i + 1]);152i++;153}154}155156continue;157}158159StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line));160tokenizer.resetSyntax();161tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE);162tokenizer.whitespaceChars(' ', ' ');163164if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)165throw new TestBug("Invalid ini file format");166167String testClassName = tokenizer.sval;168List<String> parameters = new ArrayList<String>();169170int token;171while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {172if (token == StreamTokenizer.TT_WORD) {173if (tokenizer.sval.equals("$CLASSPATH"))174parameters.add(classpath);175else176parameters.add(tokenizer.sval);177}178179if (token == StreamTokenizer.TT_NUMBER) {180parameters.add("" + tokenizer.nval);181}182}183184result.add(new Test(testClassName, parameters.toArray(new String[] {})));185}186187} catch (IOException e) {188throw new TestBug("Exception during config file parsing: " + e);189}190191if (shuffle) {192if (testWorkDir == null)193throw new TestBug("Debugger requires -testWorkDir parameter");194195Collections.shuffle(result, Utils.getRandomInstance());196197// save resulted tests sequence in file (to simplify reproducing)198try {199File file = new File(testWorkDir + File.separator + "run.tests");200file.createNewFile();201202PrintWriter writer = new PrintWriter(new FileWriter(file));203204for (Test test : result) {205writer.println(test.debuggerClassName + " " + test.argumentsToString());206}207208writer.close();209} catch (IOException e) {210throw new TestBug("Unexpected IOException: " + e);211}212}213214System.out.println("Tests execution order: ");215for (Test test : result) {216System.out.println(test.debuggerClassName + " " + test.argumentsToString());217}218219return result.toArray(new Test[] {});220}221222public void doTest() {223224stresser.start(iterations);225226try {227if (iterations == 1) {228/*229* Since many test couldn't be run in single VM twice and test config specifies only 1 iteration don't230* multiple iterations by iterations factor and execute tests once (not depending on iterations factor)231*/232executeTests();233} else {234while (stresser.continueExecution()) {235if (!executeTests()) {236// if error occured stop execution237break;238}239}240}241} finally {242stresser.finish();243}244}245246boolean executeTests() {247// maximum execution time of single test248long maxExecutionTime = 0;249250for (Test test : tests) {251long testStartTime = System.currentTimeMillis();252253TestDebuggerType2 debugger = null;254255try {256// create debugger object257Class debuggerClass = Class.forName(test.debuggerClassName);258259if (!TestDebuggerType2.class.isAssignableFrom(debuggerClass)) {260setSuccess(false);261log.complain("Invalid debugger class: " + debuggerClass);262return false;263}264265// init test debugger, pass to the debugger already created266// objects: argHandler, log, pipe, debuggee, vm267debugger = (TestDebuggerType2) debuggerClass.newInstance();268debugger.initDebugger(argHandler, log, pipe, debuggee, vm);269debugger.doInit(test.arguments, System.out);270} catch (Exception e) {271setSuccess(false);272log.complain("Unexpected exception during debugger initialization: " + e);273e.printStackTrace(log.getOutStream());274275return false;276}277278log.display("Execute debugger: " + debugger);279280// send command to the SerialExecutionDebuggee (create debuggee281// object)282pipe.println(SerialExecutionDebuggee.COMMAND_EXECUTE_DEBUGGEE + ":" + debugger.debuggeeClassName());283284// wait first READY from AbstractDebuggeeTest.doTest() (debuggee285// sends this command when it was initialized and ready for286// test)287if (!isDebuggeeReady())288return false;289290try {291// here debuggee should be ready for test and current292// debugger may perform test293debugger.doTest();294295if (debugger.getSuccess()) {296log.display("Debugger " + debugger + " finished successfully");297} else {298setSuccess(false);299log.complain("Debugger " + debugger + " finished with errors");300}301} catch (TestBug testBug) {302setSuccess(false);303log.complain("Test bug in " + debugger + ": " + testBug);304testBug.printStackTrace(log.getOutStream());305} catch (Throwable t) {306setSuccess(false);307log.complain("Unexpected exception during test execution(debugger: " + debugger + "): " + t);308t.printStackTrace(log.getOutStream());309}310311// send QUIT command to the current debuggee312pipe.println(AbstractDebuggeeTest.COMMAND_QUIT);313314if (!isDebuggeeReady())315return false;316317// send command to the SerialExecutionDebuggee318pipe.println(SerialExecutionDebuggee.COMMAND_CLEAR_DEBUGGEE);319320if (!isDebuggeeReady())321return false;322323long testExecutionTime = System.currentTimeMillis() - testStartTime;324325if (testExecutionTime > maxExecutionTime)326maxExecutionTime = testExecutionTime;327328if (maxExecutionTime > stresser.getTimeLeft()) {329log.display("WARNING: stop test execution because of timeout " +330"(max execution time for single test: " + maxExecutionTime + ", time left: " + stresser.getTimeLeft() + ")");331return false;332}333}334335return true;336}337}338339340