Path: blob/master/test/jdk/java/rmi/testlibrary/TestLibrary.java
41149 views
/*1* Copyright (c) 1998, 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*/2223/**24*25*26* @author Adrian Colley27* @author Laird Dornin28* @author Peter Jones29* @author Ann Wollrath30*31* The rmi library directory contains a set of simple utiltity classes32* for use in rmi regression tests.33*34* NOTE: The JavaTest group has recommended that regression tests do35* not make use of packages.36*/3738import java.io.ByteArrayOutputStream;39import java.io.File;40import java.io.FileInputStream;41import java.io.FileOutputStream;42import java.io.IOException;43import java.io.PrintStream;44import java.net.MalformedURLException;45import java.net.ServerSocket;46import java.net.URL;47import java.rmi.NoSuchObjectException;48import java.rmi.Remote;49import java.rmi.RemoteException;50import java.rmi.registry.LocateRegistry;51import java.rmi.registry.Registry;52import java.rmi.server.RemoteRef;53import java.rmi.server.UnicastRemoteObject;54import java.util.Enumeration;55import java.util.Properties;5657import sun.rmi.registry.RegistryImpl;58import sun.rmi.server.UnicastServerRef;59import sun.rmi.transport.Endpoint;60import sun.rmi.transport.LiveRef;61import sun.rmi.transport.tcp.TCPEndpoint;6263/**64* Class of utility/library methods (i.e. procedures) that assist with65* the writing and maintainance of rmi regression tests.66*/67public class TestLibrary {68/**69* IMPORTANT!70*71* RMI tests are run concurrently and port conflicts result when a single72* port number is used by multiple tests. When needing a port, use73* getUnusedRandomPort() wherever possible. If getUnusedRandomPort() cannot74* be used, reserve and specify a port to use for your test here. This75* will ensure there are no port conflicts amongst the RMI tests. The76* port numbers specified here may also be specified in the respective77* tests. Do not change the reserved port numbers here without also78* changing the port numbers in the respective tests.79*80* When needing an instance of the RMIRegistry, use81* createRegistryOnUnusedPort wherever possible to prevent port conflicts.82*83* Reserved port range: FIXED_PORT_MIN to FIXED_PORT_MAX (inclusive) for84* tests which cannot use a random port. If new fixed ports are added below85* FIXED_PORT_MIN or above FIXED_PORT_MAX, then adjust86* FIXED_PORT_MIN/MAX appropriately.87*/88public final static int FIXED_PORT_MIN = 60001;89public final static int FIXED_PORT_MAX = 60010;90public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 60003;91public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 60004;92public final static int READTEST_REGISTRY_PORT = 60005;93private final static int MAX_SERVER_SOCKET_TRIES = 2*(FIXED_PORT_MAX-FIXED_PORT_MIN+1);9495static void mesg(Object mesg) {96System.err.println("TEST_LIBRARY: " + mesg.toString());97}9899/**100* Routines that enable rmi tests to fail in a uniformly101* informative fashion.102*/103public static void bomb(String message, Exception e) {104String testFailed = "TEST FAILED: ";105106if ((message == null) && (e == null)) {107testFailed += " No relevant information";108} else if (e == null) {109testFailed += message;110}111112System.err.println(testFailed);113if (e != null) {114System.err.println("Test failed with: " +115e.getMessage());116e.printStackTrace(System.err);117}118throw new TestFailedException(testFailed, e);119}120public static void bomb(String message) {121bomb(message, null);122}123public static void bomb(Exception e) {124bomb(null, e);125}126127/**128* Helper method to determine if registry has started129*130* @param port The port number to check131* @param msTimeout The amount of milliseconds to spend checking132*/133134public static boolean checkIfRegistryRunning(int port, int msTimeout) {135final long POLLTIME_MS = 100L;136long stopTime = computeDeadline(System.currentTimeMillis(), msTimeout);137do {138try {139Registry r = LocateRegistry.getRegistry(port);140String[] s = r.list();141// no exception. We're now happy that registry is running142return true;143} catch (RemoteException e) {144// problem - not ready ? Try again145try {146Thread.sleep(POLLTIME_MS);147} catch (InterruptedException ie) {148// not expected149}150}151} while (System.currentTimeMillis() < stopTime);152return false;153}154155public static String getProperty(final String property,156final String defaultVal) {157try {158return java.security.AccessController.doPrivileged(159new java.security.PrivilegedAction<String>() {160public String run() {161return System.getProperty(property, defaultVal);162}163});164} catch (Exception ex) {165bomb("Exception getting property " + property, ex);166throw new AssertionError("this should be unreachable");167}168}169170public static double getTimeoutFactor() {171String prop = getProperty("test.timeout.factor", "1.0");172double timeoutFactor = 1.0;173174try {175timeoutFactor = Double.parseDouble(prop);176} catch (NumberFormatException ignore) { }177178return timeoutFactor;179}180181/**182* Computes a deadline from a timestamp and a timeout value.183* Maximum timeout (before multipliers are applied) is one hour.184*/185public static long computeDeadline(long timestamp, long timeout) {186if (timeout < 0L) {187throw new IllegalArgumentException("timeout " + timeout + "ms out of range");188}189190return timestamp + (long)(timeout * getTimeoutFactor());191}192193/**194* Property mutators195*/196public static void setBoolean(String property, boolean value) {197setProperty(property, (new Boolean(value)).toString());198}199public static void setInteger(String property, int value) {200setProperty(property, Integer.toString(value));201}202public static void setProperty(String property, String value) {203final String prop = property;204final String val = value;205java.security.AccessController.doPrivileged(206new java.security.PrivilegedAction<Void>() {207public Void run() {208System.setProperty(prop, val);209return null;210}211});212}213214/**215* Routines to print out a test's properties environment.216*/217public static void printEnvironment() {218printEnvironment(System.err);219}220public static void printEnvironment(PrintStream out) {221out.println("-------------------Test environment----------" +222"---------");223224for(Enumeration<?> keys = System.getProperties().keys();225keys.hasMoreElements();) {226227String property = (String) keys.nextElement();228out.println(property + " = " + getProperty(property, null));229}230out.println("---------------------------------------------" +231"---------");232}233234/**235* Routine that "works-around" a limitation in jtreg.236* Currently it is not possible for a test to specify that the237* test harness should build a given source file and install the238* resulting class in a location that is not accessible from the239* test's classpath. This method enables a test to move a240* compiled test class file from the test's class directory into a241* given "codebase" directory. As a result the test can only242* access the class file for <code>className</code>if the test loads243* it from a classloader (e.g. RMIClassLoader).244*245* Tests that use this routine must have the following permissions246* granted to them:247*248* getProperty user.dir249* getProperty etc.250*/251public static URL installClassInCodebase(String className,252String codebase)253throws MalformedURLException254{255return installClassInCodebase(className, codebase, true);256}257258public static URL installClassInCodebase(String className,259String codebase,260boolean delete)261throws MalformedURLException262{263/*264* NOTES/LIMITATIONS: The class must not be in a named package,265* and the codebase must be a relative path (it's created relative266* to the working directory).267*/268String classFileName = className + ".class";269270/*271* Specify the file to contain the class definition. Make sure272* that the codebase directory exists (underneath the working273* directory).274*/275File dstDir = (new File(getProperty("user.dir", "."), codebase));276277if (!dstDir.exists()) {278if (!dstDir.mkdir()) {279throw new RuntimeException(280"could not create codebase directory");281}282}283File dstFile = new File(dstDir, classFileName);284285/*286* Obtain the URL for the codebase.287*/288URL codebaseURL = dstDir.toURI().toURL();289290/*291* Specify where we will copy the class definition from, if292* necessary. After the test is built, the class file can be293* found in the "test.classes" directory.294*/295File srcDir = new File(getProperty("test.classes", "."));296File srcFile = new File(srcDir, classFileName);297298mesg(srcFile);299mesg(dstFile);300301/*302* If the class definition is not already located at the codebase,303* copy it there from the test build area.304*/305if (!dstFile.exists()) {306if (!srcFile.exists()) {307throw new RuntimeException(308"could not find class file to install in codebase " +309"(try rebuilding the test): " + srcFile);310}311312try {313copyFile(srcFile, dstFile);314} catch (IOException e) {315throw new RuntimeException(316"could not install class file in codebase");317}318319mesg("Installed class \"" + className +320"\" in codebase " + codebaseURL);321}322323/*324* After the class definition is successfully installed at the325* codebase, delete it from the test's CLASSPATH, so that it will326* not be found there first before the codebase is searched.327*/328if (srcFile.exists()) {329if (delete && !srcFile.delete()) {330throw new RuntimeException(331"could not delete duplicate class file in CLASSPATH");332}333}334335return codebaseURL;336}337338public static void copyFile(File srcFile, File dstFile)339throws IOException340{341FileInputStream src = new FileInputStream(srcFile);342FileOutputStream dst = new FileOutputStream(dstFile);343344byte[] buf = new byte[32768];345while (true) {346int count = src.read(buf);347if (count < 0) {348break;349}350dst.write(buf, 0, count);351}352353dst.close();354src.close();355}356357/** routine to unexport an object */358public static void unexport(Remote obj) {359if (obj != null) {360try {361mesg("unexporting object...");362UnicastRemoteObject.unexportObject(obj, true);363} catch (NoSuchObjectException munch) {364} catch (Exception e) {365e.getMessage();366e.printStackTrace();367}368}369}370371/**372* Allow test framework to control the security manager set in373* each test.374*375* @param managerClassName The class name of the security manager376* to be instantiated and set if no security377* manager has already been set.378*/379public static void suggestSecurityManager(String managerClassName) {380SecurityManager manager = null;381382if (System.getSecurityManager() == null) {383try {384if (managerClassName == null) {385managerClassName = TestParams.defaultSecurityManager;386}387manager = ((SecurityManager) Class.388forName(managerClassName).newInstance());389} catch (ClassNotFoundException cnfe) {390bomb("Security manager could not be found: " +391managerClassName, cnfe);392} catch (Exception e) {393bomb("Error creating security manager. ", e);394}395396System.setSecurityManager(manager);397}398}399400/**401* Creates an RMI {@link Registry} on a random, un-reserved port.402*403* @returns an RMI Registry, using a random port.404* @throws RemoteException if there was a problem creating a Registry.405*/406public static Registry createRegistryOnUnusedPort() throws RemoteException {407return LocateRegistry.createRegistry(getUnusedRandomPort());408}409410/**411* Creates an RMI {@link Registry} on an ephemeral port.412*413* @returns an RMI Registry414* @throws RemoteException if there was a problem creating a Registry.415*/416public static Registry createRegistryOnEphemeralPort() throws RemoteException {417return LocateRegistry.createRegistry(0);418}419420/**421* Returns the port number the RMI {@link Registry} is running on.422*423* @param registry the registry to find the port of.424* @return the port number the registry is using.425* @throws RuntimeException if there was a problem getting the port number.426*/427public static int getRegistryPort(Registry registry) {428int port = -1;429430try {431RemoteRef remoteRef = ((RegistryImpl)registry).getRef();432LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef();433Endpoint endpoint = liveRef.getChannel().getEndpoint();434TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint;435port = tcpEndpoint.getPort();436} catch (Exception ex) {437throw new RuntimeException("Error getting registry port.", ex);438}439440return port;441}442443/**444* Returns an unused random port number which is not a reserved port. Will445* try up to 10 times to get a random port before giving up and throwing a446* RuntimeException.447*448* @return an unused random port number.449* @throws RuntimeException if there was a problem getting a port.450*/451public static int getUnusedRandomPort() {452int numTries = 0;453IOException ex = null;454455while (numTries++ < MAX_SERVER_SOCKET_TRIES) {456int unusedRandomPort = -1;457ex = null; //reset458459try (ServerSocket ss = new ServerSocket(0)) {460unusedRandomPort = ss.getLocalPort();461} catch (IOException e) {462ex = e;463// temporarily print stack trace here until we find out why464// tests are failing.465System.err.println("TestLibrary.getUnusedRandomPort() caught "466+ "exception on iteration " + numTries467+ (numTries==MAX_SERVER_SOCKET_TRIES ? " (the final try)."468: "."));469ex.printStackTrace();470}471472if (unusedRandomPort >= 0) {473if (isReservedPort(unusedRandomPort)) {474System.out.println("INFO: On try # " + numTries475+ (numTries==MAX_SERVER_SOCKET_TRIES ? ", the final try, ": ",")476+ " ServerSocket(0) returned the reserved port "477+ unusedRandomPort478+ " in TestLibrary.getUnusedRandomPort() ");479} else {480return unusedRandomPort;481}482}483}484485// If we're here, then either an exception was thrown or the port is486// a reserved port.487if (ex==null) {488throw new RuntimeException("Error getting unused random port. The"489+" last port returned by ServerSocket(0) was a reserved port");490} else {491throw new RuntimeException("Error getting unused random port.", ex);492}493}494495/**496* Determines if a port is one of the reserved port numbers.497*498* @param port the port to test.499* @return {@code true} if the port is a reserved port, otherwise500* {@code false}.501*/502public static boolean isReservedPort(int port) {503return ((port >= FIXED_PORT_MIN) && (port <= FIXED_PORT_MAX) ||504(port == 1099));505}506507/**508* Method to capture the stack trace of an exception and return it509* as a string.510*/511public String stackTraceToString(Exception e) {512ByteArrayOutputStream bos = new ByteArrayOutputStream();513PrintStream ps = new PrintStream(bos);514515e.printStackTrace(ps);516return bos.toString();517}518519/** extra properties */520private static Properties props;521522/**523* Returns extra test properties. Looks for the file "../../test.props"524* and reads it in as a Properties file. Assuming the working directory525* is "<path>/JTwork/scratch", this will find "<path>/test.props".526*/527private static synchronized Properties getExtraProperties() {528if (props != null) {529return props;530}531props = new Properties();532File f = new File(".." + File.separator + ".." + File.separator +533"test.props");534if (!f.exists()) {535return props;536}537try {538FileInputStream in = new FileInputStream(f);539try {540props.load(in);541} finally {542in.close();543}544} catch (IOException e) {545e.printStackTrace();546throw new RuntimeException("extra property setup failed", e);547}548return props;549}550551/**552* Returns an extra test property. Looks for the file "../../test.props"553* and reads it in as a Properties file. Assuming the working directory554* is "<path>/JTwork/scratch", this will find "<path>/test.props".555* If the property isn't found, defaultVal is returned.556*/557public static String getExtraProperty(String property, String defaultVal) {558return getExtraProperties().getProperty(property, defaultVal);559}560}561562563