Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java
40948 views
/*1* Copyright (c) 2002, 2018, 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*/2223package nsk.share;2425import java.io.*;26import java.lang.reflect.Method;27import java.util.*;2829/**30* Class used as an agent for Java serviceability reliability testing (RAS).31* It sets different RAS options and/or modes for a special agent which32* actually performs the specified RAS testing.<br>33* The agent recognizes arguments, started with ''<code>-ras.</code>''. They34* may be as follows:<p>35* <li><code>-ras.help</code> - print usage message and exit36* <li><code>-ras.verbose</code> - verbose mode37* <li><code>-ras.invoke_run</code> - invoke the method <i>run(String[],PrintStream)</i>38* of the test instead of <i>main(String[])</i> which is invoked by default.39* <li><code>-ras.hotswap=<stress_level></code> - enable JVMTI hotswap of40* the currently running test classes. Here are the possible HotSwap stress41* levels:<br>42* 0 - HotSwap off<br>43* 2 - HotSwap tested class in every JVMTI method entry event of running test44* (default mode)<br>45* 20 - HotSwap tested class in every JVMTI method entry event of every class<br>46* 3 - HotSwap tested class in every JVMTI single step event of running test<br>47* 4 - HotSwap tested class in every JVMTI exception event of running test<br>48* 40 - HotSwap tested class in every JVMTI exception event of every class<p>49*/50public class RASagent {51static final int HOTSWAP_OFF = 0;52static final int HOTSWAP_EVERY_METHOD_ENTRY = 2;53static final int HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS = 20;54static final int HOTSWAP_EVERY_SINGLE_STEP = 3;55static final int HOTSWAP_EVERY_EXCEPTION = 4;56static final int HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS = 40;5758// path to the directory with class files of the invoked test59static String clfBasePath = null;6061private static boolean verbose = false;6263private static PrintStream out;6465native static int setHotSwapMode(boolean vrb, int stress_lev,66String shortName);6768public static void main(String argv[]) {69System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);70}7172public static int run(String argv[], PrintStream out) {73return new RASagent().runThis(argv, out);74}7576private int runThis(String argv[], PrintStream out) {77int skipArgs = 1; // number of arguments which must be skipped78// for the invoked test79boolean invokeRun = false; // invoke the method "main" by default80int hotSwapMode = HOTSWAP_EVERY_METHOD_ENTRY; // HotSwap default stress level81int res;82String hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY";8384RASagent.out = out;8586if (argv.length != 0) {87// parse arguments for the RASagent and then skip them88while(argv[skipArgs-1].startsWith("-ras.")) {89if (argv[skipArgs-1].equals("-ras.verbose")) {90verbose = true;91} else if (argv[skipArgs-1].equals("-ras.help")) {92printHelp();93return Consts.TEST_FAILED;94} else if (argv[skipArgs-1].equals("-ras.invoke_run")) {95invokeRun = true;96} else if (argv[skipArgs-1].startsWith("-ras.hotswap=")) {97try {98hotSwapMode = Integer.parseInt(99argv[skipArgs-1].substring(argv[skipArgs-1].lastIndexOf("=")+1));100} catch (NumberFormatException e) {101e.printStackTrace();102out.println("\nERROR: RASagent: specified HotSwap mode \""103+ hotSwapMode + "\" is not an integer");104printHelp();105return Consts.TEST_FAILED;106}107switch(hotSwapMode) {108case HOTSWAP_EVERY_METHOD_ENTRY:109hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY";110break;111case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS:112hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS";113break;114case HOTSWAP_EVERY_SINGLE_STEP:115hotSwapModeName = "HOTSWAP_EVERY_SINGLE_STEP";116break;117case HOTSWAP_EVERY_EXCEPTION:118hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION";119break;120case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS:121hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS";122break;123default:124out.println("\nERROR: RASagent: specified HotSwap mode \""125+ hotSwapMode + "\" is unrecognized");126printHelp();127return Consts.TEST_FAILED;128}129}130skipArgs++;131}132133String shortTestName = getTestNameAndPath(argv[skipArgs-1]);134135display("\n#### RASagent: setting hotswap mode \""136+ hotSwapModeName + "\" for class \""137+ shortTestName + "\" ...");138if ((res = setHotSwapMode(verbose, hotSwapMode, shortTestName)) != 0) {139out.println("\nERROR: RASagent: unable to set HotSwap stress level for \""140+ shortTestName + "\", exiting");141return Consts.TEST_FAILED;142}143display("\n#### RASagent: ... setting hotswap mode done");144145try {146Class testCls = Class.forName(argv[skipArgs-1]);147display("\n#### RASagent: main class \""148+ testCls.toString() + "\" loaded");149150// copy arguments for the invoked test151String args[] = new String[argv.length-skipArgs];152System.arraycopy(argv, skipArgs, args, 0, args.length);153154// invoke the test155if (invokeRun)156return invokeRunMethod(testCls, args);157else158return invokeMainMethod(testCls, args);159} catch(ClassNotFoundException e) {160// just pass: the invoked test is already a RAS specific one161out.println("\nWARNING: the test was not really run due to the following error:"162+ "\n\tunable to get the Class object for \""163+ argv[skipArgs-1] + "\"\n\tcaught: " + e);164return Consts.TEST_PASSED;165}166167} else {168out.println("\nERROR: RASagent: required test name is absent in parameters list");169return Consts.TEST_FAILED;170}171}172173/**174* Verify that test's class file exists with a path given as a parameter175* and, if so, store that path in the static field "clfBasePath".176*/177private boolean pathValid(String pathToCheck, String testName) {178String fullPath = pathToCheck + File.separator179+ testName.replace('.', File.separatorChar) + ".class";180File classFile = null;181182display("\n#### RASagent: verifying class path\n<RASagent>\t"183+ pathToCheck + " ...");184try {185classFile = new File(fullPath);186} catch (NullPointerException e) {187e.printStackTrace();188out.println("\nERROR: RASagent: verification of class file "189+ fullPath + " failed: caught " + e);190System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);191}192193if (classFile.exists()) {194clfBasePath = pathToCheck;195display("<RASagent>\tthe class file exists:\n<RASagent>\t\t"196+ fullPath + "\n<RASagent>\tclass file base directory found:\n"197+ "<RASagent>\t\t" + clfBasePath198+ "\n#### RASagent: ... class path verification done\n");199return true;200}201else {202display("<RASagent>\tno class file at location :\n\t\t"203+ fullPath204+ "\n#### RASagent: ... class path verification done\n");205return false;206}207}208209/**210* Get short name of an invoked test (i.e. without package name) and211* store path to the directory with the test's class files.212*/213private String getTestNameAndPath(String testName) {214String shortTestName = testName;215String packageName = "";216217// if '.' occurs, it means that current test is inside a package218if (testName.lastIndexOf(".") != -1) {219shortTestName = testName.substring(testName.lastIndexOf(".")+1);220packageName = testName.substring(0, testName.lastIndexOf("."));221}222223StringTokenizer clPathes = new StringTokenizer(224System.getProperty("java.class.path"), File.pathSeparator);225226while(clPathes.hasMoreTokens()) {227String clPath = clPathes.nextToken();228229// trying to load a class file defining the current test from230// this entry of "java.class.path": the class file may locate231// at the test's work directory or if it's already compiled,232// at any directory in classpath233if (pathValid(clPath, testName))234return shortTestName;235}236237// directory with the test's class files was not found.238// Actually, it means that the invoked test has own Java239// options such as, for example, "-verify"240out.println("\nWARNING: the test was not really run due to the following reason:"241+ "\n\tthe invoked test has the own Java option: "242+ testName);243System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);244245return null; // fake return for too smart javac246}247248/**249* Invoke the method <i>main(String[])</i> of the test.250*/251private int invokeMainMethod(Class testCls, String args[]) {252Class[] methType = { String[].class };253Object[] methArgs = { args };254255return invokeMethod(testCls, "main", methType, methArgs);256}257258/**259* Invoke the method <i>run(String[], PrintStream)</i> of the test.260*/261private int invokeRunMethod(Class testCls, String args[]) {262Class[] methType = { String[].class, PrintStream.class };263Object[] methArgs = { args, out };264265return invokeMethod(testCls, "run", methType, methArgs);266}267268/**269* Low level invocation of the test.270*/271private int invokeMethod(Class<?> testCls, String methodName,272Class methType[], Object methArgs[]) {273274try {275Method testMeth = testCls.getMethod(methodName, methType);276display("\n#### RASagent: invoking method \""277+ testMeth.toString() + "\" ...");278279Object result = testMeth.invoke(null, methArgs);280281display("\n#### RASagent: ... invocation of \""282+ testMeth.toString() + "\" done");283if (result instanceof Integer) {284Integer retCode = (Integer) result;285return retCode.intValue();286}287} catch(NoSuchMethodException e) {288e.printStackTrace();289out.println("\nFAILURE: RASagent: unable to get method \""290+ methodName + "\" in class "291+ testCls + "\n\tcaught " + e);292return Consts.TEST_FAILED;293} catch(Exception e) {294e.printStackTrace();295out.println("\nFAILURE: RASagent: caught during invokation of the test class "296+ testCls + " " + e);297return Consts.TEST_FAILED;298}299300return -1;301}302303/**304* Load class bytes for HotSwap.305*/306static byte[] loadFromClassFile(String signature) {307String testPath = clfBasePath + File.separator + signature.substring(3081, signature.length()-1).replace('/', File.separatorChar) + ".class";309File classFile = null;310311display("\n#### RASagent: looking for class file\n<RASagent>\t"312+ testPath + " ...");313314try {315classFile = new File(testPath);316} catch (NullPointerException e) {317out.println("\nFAILURE: RASagent: path name to the redefining class file is null");318}319320display("\n#### RASagent: loading " + classFile.length()321+ " bytes from class file "+ testPath + " ...");322byte[] buf = new byte[(int) classFile.length()];323try {324InputStream in = new FileInputStream(classFile);325in.read(buf);326in.close();327} catch(FileNotFoundException e) {328e.printStackTrace();329out.println("\nFAILURE: RASagent: loadFromClassFile: file " +330classFile.getName() + " not found");331System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);332} catch (Exception e) {333e.printStackTrace();334out.println("\nFAILURE: RASagent: unable to load bytes from the file:\n");335out.println("\t" + testPath + ": caught " + e);336System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);337}338339display("\n#### RASagent: ... " + classFile.length() + " bytes loaded");340341return buf;342}343344/**345* This method is used in verbose mode. It prints paramter string only346* in case of verbose mode.347*/348private static void display(String msg) {349if (verbose)350out.println(msg);351}352353/**354* This method prints out RASagent usage message.355*/356private static void printHelp() {357out.println("\nRASagent usage: RASagent [option, ...] test" +358"\n\t-ras.help print this message and exit" +359"\n\t-ras.verbose verbose mode (off by default)" +360"\n\t-ras.hotswap=mode enable HotSwap of the running test classes" +361"\n\t\twhere mode is:" +362"\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY363+ " - hotswap tested class in its every method entry event" +364"\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS365+ " - hotswap tested class in every method entry event for every class" +366"\n\t\t\t" + HOTSWAP_EVERY_SINGLE_STEP367+ " - hotswap tested class in its every single step event" +368"\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION369+ " - hotswap tested class in its every exception event" +370"\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS371+ " - hotswap tested class in every exception event for every class\n" +372"\n\t-ras.invoke_run invoke the method run() of the test" +373"\n\t\tinstead of main() by default");374}375}376377378