diff -r c63bdf53a1a7 -r 44839fbb20db test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java Mon Apr 30 18:10:24 2018 -0700 @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2002, 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; + +import java.io.*; +import java.lang.reflect.Method; +import java.util.*; + +/** + * Class used as an agent for Java serviceability reliability testing (RAS). + * It sets different RAS options and/or modes for a special agent which + * actually performs the specified RAS testing.
+ * The agent recognizes arguments, started with ''-ras.''. They + * may be as follows:

+ *

  • -ras.help - print usage message and exit + *
  • -ras.verbose - verbose mode + *
  • -ras.invoke_run - invoke the method run(String[],PrintStream) + * of the test instead of main(String[]) which is invoked by default. + *
  • -ras.hotswap=<stress_level> - enable JVMTI hotswap of + * the currently running test classes. Here are the possible HotSwap stress + * levels:
    + * 0 - HotSwap off
    + * 2 - HotSwap tested class in every JVMTI method entry event of running test + * (default mode)
    + * 20 - HotSwap tested class in every JVMTI method entry event of every class
    + * 3 - HotSwap tested class in every JVMTI single step event of running test
    + * 4 - HotSwap tested class in every JVMTI exception event of running test
    + * 40 - HotSwap tested class in every JVMTI exception event of every class

    + */ +public class RASagent { + static final int HOTSWAP_OFF = 0; + static final int HOTSWAP_EVERY_METHOD_ENTRY = 2; + static final int HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS = 20; + static final int HOTSWAP_EVERY_SINGLE_STEP = 3; + static final int HOTSWAP_EVERY_EXCEPTION = 4; + static final int HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS = 40; + + // path to the directory with class files of the invoked test + static String clfBasePath = null; + + private static boolean verbose = false; + + private static PrintStream out; + + native static int setHotSwapMode(boolean vrb, int stress_lev, + String shortName); + + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new RASagent().runThis(argv, out); + } + + private int runThis(String argv[], PrintStream out) { + int skipArgs = 1; // number of arguments which must be skipped + // for the invoked test + boolean invokeRun = false; // invoke the method "main" by default + int hotSwapMode = HOTSWAP_EVERY_METHOD_ENTRY; // HotSwap default stress level + int res; + String hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY"; + + RASagent.out = out; + + if (argv.length != 0) { + // parse arguments for the RASagent and then skip them + while(argv[skipArgs-1].startsWith("-ras.")) { + if (argv[skipArgs-1].equals("-ras.verbose")) { + verbose = true; + } else if (argv[skipArgs-1].equals("-ras.help")) { + printHelp(); + return Consts.TEST_FAILED; + } else if (argv[skipArgs-1].equals("-ras.invoke_run")) { + invokeRun = true; + } else if (argv[skipArgs-1].startsWith("-ras.hotswap=")) { + try { + hotSwapMode = Integer.parseInt( + argv[skipArgs-1].substring(argv[skipArgs-1].lastIndexOf("=")+1)); + } catch (NumberFormatException e) { + e.printStackTrace(); + out.println("\nERROR: RASagent: specified HotSwap mode \"" + + hotSwapMode + "\" is not an integer"); + printHelp(); + return Consts.TEST_FAILED; + } + switch(hotSwapMode) { + case HOTSWAP_EVERY_METHOD_ENTRY: + hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY"; + break; + case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS: + hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS"; + break; + case HOTSWAP_EVERY_SINGLE_STEP: + hotSwapModeName = "HOTSWAP_EVERY_SINGLE_STEP"; + break; + case HOTSWAP_EVERY_EXCEPTION: + hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION"; + break; + case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS: + hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS"; + break; + default: + out.println("\nERROR: RASagent: specified HotSwap mode \"" + + hotSwapMode + "\" is unrecognized"); + printHelp(); + return Consts.TEST_FAILED; + } + } + skipArgs++; + } + + String shortTestName = getTestNameAndPath(argv[skipArgs-1]); + + display("\n#### RASagent: setting hotswap mode \"" + + hotSwapModeName + "\" for class \"" + + shortTestName + "\" ..."); + if ((res = setHotSwapMode(verbose, hotSwapMode, shortTestName)) != 0) { + out.println("\nERROR: RASagent: unable to set HotSwap stress level for \"" + + shortTestName + "\", exiting"); + return Consts.TEST_FAILED; + } + display("\n#### RASagent: ... setting hotswap mode done"); + + try { + Class testCls = Class.forName(argv[skipArgs-1]); + display("\n#### RASagent: main class \"" + + testCls.toString() + "\" loaded"); + + // copy arguments for the invoked test + String args[] = new String[argv.length-skipArgs]; + System.arraycopy(argv, skipArgs, args, 0, args.length); + + // invoke the test + if (invokeRun) + return invokeRunMethod(testCls, args); + else + return invokeMainMethod(testCls, args); + } catch(ClassNotFoundException e) { + // just pass: the invoked test is already a RAS specific one + out.println("\nWARNING: the test was not really run due to the following error:" + + "\n\tunable to get the Class object for \"" + + argv[skipArgs-1] + "\"\n\tcaught: " + e); + return Consts.TEST_PASSED; + } + + } else { + out.println("\nERROR: RASagent: required test name is absent in parameters list"); + return Consts.TEST_FAILED; + } + } + + /** + * Verify that test's class file exists with a path given as a parameter + * and, if so, store that path in the static field "clfBasePath". + */ + private boolean pathValid(String pathToCheck, String testName) { + String fullPath = pathToCheck + File.separator + + testName.replace('.', File.separatorChar) + ".class"; + File classFile = null; + + display("\n#### RASagent: verifying class path\n\t" + + pathToCheck + " ..."); + try { + classFile = new File(fullPath); + } catch (NullPointerException e) { + e.printStackTrace(); + out.println("\nERROR: RASagent: verification of class file " + + fullPath + " failed: caught " + e); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + if (classFile.exists()) { + clfBasePath = pathToCheck; + display("\tthe class file exists:\n\t\t" + + fullPath + "\n\tclass file base directory found:\n" + + "\t\t" + clfBasePath + + "\n#### RASagent: ... class path verification done\n"); + return true; + } + else { + display("\tno class file at location :\n\t\t" + + fullPath + + "\n#### RASagent: ... class path verification done\n"); + return false; + } + } + + /** + * Get short name of an invoked test (i.e. without package name) and + * store path to the directory with the test's class files. + */ + private String getTestNameAndPath(String testName) { + String shortTestName = testName; + String packageName = ""; + + // if '.' occurs, it means that current test is inside a package + if (testName.lastIndexOf(".") != -1) { + shortTestName = testName.substring(testName.lastIndexOf(".")+1); + packageName = testName.substring(0, testName.lastIndexOf(".")); + } + + StringTokenizer clPathes = new StringTokenizer( + System.getProperty("java.class.path"), File.pathSeparator); + + while(clPathes.hasMoreTokens()) { + String clPath = clPathes.nextToken(); + + // trying to load a class file defining the current test from + // this entry of "java.class.path": the class file may locate + // at the test's work directory or if it's already compiled, + // at any directory in classpath + if (pathValid(clPath, testName)) + return shortTestName; + } + + // directory with the test's class files was not found. + // Actually, it means that the invoked test has own Java + // options such as, for example, "-verify" + out.println("\nWARNING: the test was not really run due to the following reason:" + + "\n\tthe invoked test has the own Java option: " + + testName); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED); + + return null; // fake return for too smart javac + } + + /** + * Invoke the method main(String[]) of the test. + */ + private int invokeMainMethod(Class testCls, String args[]) { + Class[] methType = { String[].class }; + Object[] methArgs = { args }; + + return invokeMethod(testCls, "main", methType, methArgs); + } + + /** + * Invoke the method run(String[], PrintStream) of the test. + */ + private int invokeRunMethod(Class testCls, String args[]) { + Class[] methType = { String[].class, PrintStream.class }; + Object[] methArgs = { args, out }; + + return invokeMethod(testCls, "run", methType, methArgs); + } + + /** + * Low level invocation of the test. + */ + private int invokeMethod(Class testCls, String methodName, + Class methType[], Object methArgs[]) { + + try { + Method testMeth = testCls.getMethod(methodName, methType); + display("\n#### RASagent: invoking method \"" + + testMeth.toString() + "\" ..."); + + Object result = testMeth.invoke(null, methArgs); + + display("\n#### RASagent: ... invocation of \"" + + testMeth.toString() + "\" done"); + if (result instanceof Integer) { + Integer retCode = (Integer) result; + return retCode.intValue(); + } + } catch(NoSuchMethodException e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: unable to get method \"" + + methodName + "\" in class " + + testCls + "\n\tcaught " + e); + return Consts.TEST_FAILED; + } catch(Exception e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: caught during invokation of the test class " + + testCls + " " + e); + return Consts.TEST_FAILED; + } + + return -1; + } + + /** + * Load class bytes for HotSwap. + */ + static byte[] loadFromClassFile(String signature) { + String testPath = clfBasePath + File.separator + signature.substring( + 1, signature.length()-1).replace('/', File.separatorChar) + ".class"; + File classFile = null; + + display("\n#### RASagent: looking for class file\n\t" + + testPath + " ..."); + + try { + classFile = new File(testPath); + } catch (NullPointerException e) { + out.println("\nFAILURE: RASagent: path name to the redefining class file is null"); + } + + display("\n#### RASagent: loading " + classFile.length() + + " bytes from class file "+ testPath + " ..."); + byte[] buf = new byte[(int) classFile.length()]; + try { + InputStream in = new FileInputStream(classFile); + in.read(buf); + in.close(); + } catch(FileNotFoundException e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: loadFromClassFile: file " + + classFile.getName() + " not found"); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } catch (Exception e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: unable to load bytes from the file:\n"); + out.println("\t" + testPath + ": caught " + e); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + display("\n#### RASagent: ... " + classFile.length() + " bytes loaded"); + + return buf; + } + + /** + * This method is used in verbose mode. It prints paramter string only + * in case of verbose mode. + */ + private static void display(String msg) { + if (verbose) + out.println(msg); + } + + /** + * This method prints out RASagent usage message. + */ + private static void printHelp() { + out.println("\nRASagent usage: RASagent [option, ...] test" + + "\n\t-ras.help print this message and exit" + + "\n\t-ras.verbose verbose mode (off by default)" + + "\n\t-ras.hotswap=mode enable HotSwap of the running test classes" + + "\n\t\twhere mode is:" + + "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY + + " - hotswap tested class in its every method entry event" + + "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS + + " - hotswap tested class in every method entry event for every class" + + "\n\t\t\t" + HOTSWAP_EVERY_SINGLE_STEP + + " - hotswap tested class in its every single step event" + + "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION + + " - hotswap tested class in its every exception event" + + "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS + + " - hotswap tested class in every exception event for every class\n" + + "\n\t-ras.invoke_run invoke the method run() of the test" + + "\n\t\tinstead of main() by default"); + } +}