test/java/rmi/testlibrary/TestLibrary.java

Print this page
rev 6154 : 8004317: TestLibrary.getUnusedRandomPort() fails intermittently, but exception not reported
Summary: Improve exception handling & reporting to enable diagnosis of failure
Reviewed-by: duke


  37  */
  38 
  39 import java.io.ByteArrayOutputStream;
  40 import java.io.File;
  41 import java.io.FileInputStream;
  42 import java.io.FileOutputStream;
  43 import java.io.IOException;
  44 import java.io.PrintStream;
  45 import java.net.MalformedURLException;
  46 import java.net.ServerSocket;
  47 import java.net.URL;
  48 import java.rmi.NoSuchObjectException;
  49 import java.rmi.Remote;
  50 import java.rmi.RemoteException;
  51 import java.rmi.registry.LocateRegistry;
  52 import java.rmi.registry.Registry;
  53 import java.rmi.server.RemoteRef;
  54 import java.rmi.server.UnicastRemoteObject;
  55 import java.util.Enumeration;
  56 import java.util.Properties;

  57 import sun.rmi.registry.RegistryImpl;
  58 import sun.rmi.server.UnicastServerRef;
  59 import sun.rmi.transport.Endpoint;
  60 import sun.rmi.transport.LiveRef;
  61 import sun.rmi.transport.tcp.TCPEndpoint;
  62 
  63 /**
  64  * Class of utility/library methods (i.e. procedures) that assist with
  65  * the writing and maintainance of rmi regression tests.
  66  */
  67 public class TestLibrary {
  68     /**
  69      *                       IMPORTANT!
  70      *
  71      * RMI tests are run concurrently and port conflicts result when a single
  72      * port number is used by multiple tests.  When needing a port, use
  73      * getUnusedRandomPort() wherever possible.  If getUnusedRandomPort() cannot
  74      * be used, reserve and specify a port to use for your test here.   This
  75      * will ensure there are no port conflicts amongst the RMI tests.  The
  76      * port numbers specified here may also be specified in the respective
  77      * tests.  Do not change the reserved port numbers here without also
  78      * changing the port numbers in the respective tests.
  79      *
  80      * When needing an instance of the RMIRegistry, use
  81      * createRegistryOnUnusedPort wherever possible to prevent port conflicts.
  82      *
  83      * Reserved port range: FIXED_PORT_MIN to FIXED_PORT_MAX (inclusive) for
  84      * tests which cannot use a random port.  If new fixed ports are added below
  85      * FIXED_PORT_MIN or above FIXED_PORT_MAX, then adjust
  86      * FIXED_PORT_MIN/MAX appropriately.
  87      */
  88     public final static int FIXED_PORT_MIN = 64001;
  89     public final static int FIXED_PORT_MAX = 64010;
  90     public final static int RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT = 64001;
  91     public final static int RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT = 64002;
  92     public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 64003;
  93     public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 64004;
  94     public final static int READTEST_REGISTRY_PORT = 64005;

  95 
  96     static void mesg(Object mesg) {
  97         System.err.println("TEST_LIBRARY: " + mesg.toString());
  98     }
  99 
 100     /**
 101      * Routines that enable rmi tests to fail in a uniformly
 102      * informative fashion.
 103      */
 104     public static void bomb(String message, Exception e) {
 105         String testFailed = "TEST FAILED: ";
 106 
 107         if ((message == null) && (e == null)) {
 108             testFailed += " No relevant information";
 109         } else if (e == null) {
 110             testFailed += message;
 111         }
 112 
 113         System.err.println(testFailed);
 114         if (e != null) {
 115             System.err.println("Test failed with: " +
 116                                e.getMessage());
 117             e.printStackTrace(System.err);
 118         }
 119         throw new TestFailedException(testFailed, e);
 120     }
 121     public static void bomb(String message) {
 122         bomb(message, null);
 123     }
 124     public static void bomb(Exception e) {
 125         bomb(null, e);
 126     }
 127 
 128     /**
 129      * Property accessors
 130      */
 131     private static boolean getBoolean(String name) {
 132         return (new Boolean(getProperty(name, "false")).booleanValue());
 133     }
 134     private static Integer getInteger(String name) {
 135         int val = 0;
 136         Integer value = null;
 137 
 138         String propVal = getProperty(name, null);
 139         if (propVal == null) {
 140             return null;
 141         }
 142 
 143         try {
 144             value = new Integer(Integer.parseInt(propVal));
 145         } catch (NumberFormatException nfe) {
 146         }
 147         return value;
 148     }
 149     public static String getProperty(String property, String defaultVal) {
 150         final String prop = property;
 151         final String def = defaultVal;
 152         return ((String) java.security.AccessController.doPrivileged
 153             (new java.security.PrivilegedAction() {
 154                 public Object run() {
 155                     return System.getProperty(prop, def);
 156                 }
 157             }));
 158     }
 159 
 160     /**
 161      * Property mutators
 162      */
 163     public static void setBoolean(String property, boolean value) {
 164         setProperty(property, (new Boolean(value)).toString());
 165     }
 166     public static void setInteger(String property, int value) {
 167         setProperty(property, Integer.toString(value));
 168     }
 169     public static void setProperty(String property, String value) {
 170         final String prop = property;
 171         final String val = value;
 172         java.security.AccessController.doPrivileged
 173             (new java.security.PrivilegedAction() {
 174                 public Object run() {
 175                     System.setProperty(prop, val);
 176                     return null;
 177                 }
 178         });
 179     }
 180 
 181     /**
 182      * Routines to print out a test's properties environment.
 183      */
 184     public static void printEnvironment() {
 185         printEnvironment(System.err);
 186     }
 187     public static void printEnvironment(PrintStream out) {
 188         out.println("-------------------Test environment----------" +
 189                     "---------");
 190 
 191         for(Enumeration keys = System.getProperties().keys();
 192             keys.hasMoreElements();) {
 193 
 194             String property = (String) keys.nextElement();
 195             out.println(property + " = " + getProperty(property, null));
 196         }
 197         out.println("---------------------------------------------" +
 198                     "---------");
 199     }
 200 
 201     /**
 202      * Routine that "works-around" a limitation in jtreg.
 203      * Currently it is not possible for a test to specify that the
 204      * test harness should build a given source file and install the
 205      * resulting class in a location that is not accessible from the
 206      * test's classpath.  This method enables a test to move a
 207      * compiled test class file from the test's class directory into a
 208      * given "codebase" directory.  As a result the test can only
 209      * access the class file for <code>className</code>if the test loads
 210      * it from a classloader (e.g. RMIClassLoader).
 211      *


 235         String classFileName = className + ".class";
 236 
 237         /*
 238          * Specify the file to contain the class definition.  Make sure
 239          * that the codebase directory exists (underneath the working
 240          * directory).
 241          */
 242         File dstDir = (new File(getProperty("user.dir", "."), codebase));
 243 
 244         if (!dstDir.exists()) {
 245             if (!dstDir.mkdir()) {
 246                 throw new RuntimeException(
 247                     "could not create codebase directory");
 248             }
 249         }
 250         File dstFile = new File(dstDir, classFileName);
 251 
 252         /*
 253          * Obtain the URL for the codebase.
 254          */
 255         URL codebaseURL = dstDir.toURL();
 256 
 257         /*
 258          * Specify where we will copy the class definition from, if
 259          * necessary.  After the test is built, the class file can be
 260          * found in the "test.classes" directory.
 261          */
 262         File srcDir = new File(getProperty("test.classes", "."));
 263         File srcFile = new File(srcDir, classFileName);
 264 
 265         mesg(srcFile);
 266         mesg(dstFile);
 267 
 268         /*
 269          * If the class definition is not already located at the codebase,
 270          * copy it there from the test build area.
 271          */
 272         if (!dstFile.exists()) {
 273             if (!srcFile.exists()) {
 274                 throw new RuntimeException(
 275                     "could not find class file to install in codebase " +


 390             Endpoint endpoint = liveRef.getChannel().getEndpoint();
 391             TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint;
 392             port = tcpEndpoint.getPort();
 393         } catch (Exception ex) {
 394             throw new RuntimeException("Error getting registry port.", ex);
 395         }
 396 
 397         return port;
 398     }
 399 
 400     /**
 401      * Returns an unused random port number which is not a reserved port.  Will
 402      * try up to 10 times to get a random port before giving up and throwing a
 403      * RuntimeException.
 404      *
 405      * @return an unused random port number.
 406      * @throws RuntimeException if there was a problem getting a port.
 407      */
 408     public static int getUnusedRandomPort() {
 409         int numTries = 0;
 410         int unusedRandomPort = FIXED_PORT_MIN;
 411         Exception ex = null;
 412 
 413         while (numTries++ < 10) {
 414             ex = null; //reset
 415 
 416             try (ServerSocket ss = new ServerSocket(0)) {
 417                 unusedRandomPort = ss.getLocalPort();
 418             } catch (Exception e) {
 419                 ex = e;
 420             }
 421 
 422             if (!isReservedPort(unusedRandomPort)) {














 423                 return unusedRandomPort;
 424             }
 425         }

 426 
 427         // If we're here, then either an exception was thrown or the port is
 428         // a reserved port.




 429         throw new RuntimeException("Error getting unused random port.", ex);

 430     }
 431 
 432     /**
 433      * Determines if a port is one of the reserved port numbers.
 434      *
 435      * @param port the port to test.
 436      * @return {@code true} if the port is a reserved port, otherwise
 437      *         {@code false}.
 438      */
 439     public static boolean isReservedPort(int port) {
 440         return ((port >= FIXED_PORT_MIN) && (port <= FIXED_PORT_MAX) ||
 441                 (port == 1099));
 442     }
 443 
 444     /**
 445      * Method to capture the stack trace of an exception and return it
 446      * as a string.
 447      */
 448     public String stackTraceToString(Exception e) {
 449         ByteArrayOutputStream bos = new ByteArrayOutputStream();




  37  */
  38 
  39 import java.io.ByteArrayOutputStream;
  40 import java.io.File;
  41 import java.io.FileInputStream;
  42 import java.io.FileOutputStream;
  43 import java.io.IOException;
  44 import java.io.PrintStream;
  45 import java.net.MalformedURLException;
  46 import java.net.ServerSocket;
  47 import java.net.URL;
  48 import java.rmi.NoSuchObjectException;
  49 import java.rmi.Remote;
  50 import java.rmi.RemoteException;
  51 import java.rmi.registry.LocateRegistry;
  52 import java.rmi.registry.Registry;
  53 import java.rmi.server.RemoteRef;
  54 import java.rmi.server.UnicastRemoteObject;
  55 import java.util.Enumeration;
  56 import java.util.Properties;
  57 
  58 import sun.rmi.registry.RegistryImpl;
  59 import sun.rmi.server.UnicastServerRef;
  60 import sun.rmi.transport.Endpoint;
  61 import sun.rmi.transport.LiveRef;
  62 import sun.rmi.transport.tcp.TCPEndpoint;
  63 
  64 /**
  65  * Class of utility/library methods (i.e. procedures) that assist with
  66  * the writing and maintainance of rmi regression tests.
  67  */
  68 public class TestLibrary {
  69     /**
  70      *                       IMPORTANT!
  71      *
  72      * RMI tests are run concurrently and port conflicts result when a single
  73      * port number is used by multiple tests.  When needing a port, use
  74      * getUnusedRandomPort() wherever possible.  If getUnusedRandomPort() cannot
  75      * be used, reserve and specify a port to use for your test here.   This
  76      * will ensure there are no port conflicts amongst the RMI tests.  The
  77      * port numbers specified here may also be specified in the respective
  78      * tests.  Do not change the reserved port numbers here without also
  79      * changing the port numbers in the respective tests.
  80      *
  81      * When needing an instance of the RMIRegistry, use
  82      * createRegistryOnUnusedPort wherever possible to prevent port conflicts.
  83      *
  84      * Reserved port range: FIXED_PORT_MIN to FIXED_PORT_MAX (inclusive) for
  85      * tests which cannot use a random port.  If new fixed ports are added below
  86      * FIXED_PORT_MIN or above FIXED_PORT_MAX, then adjust
  87      * FIXED_PORT_MIN/MAX appropriately.
  88      */
  89     public final static int FIXED_PORT_MIN = 64001;
  90     public final static int FIXED_PORT_MAX = 64010;
  91     public final static int RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT = 64001;
  92     public final static int RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT = 64002;
  93     public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 64003;
  94     public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 64004;
  95     public final static int READTEST_REGISTRY_PORT = 64005;
  96     private final static int MAX_SERVER_SOCKET_TRIES = 10;
  97 
  98     static void mesg(Object mesg) {
  99         System.err.println("TEST_LIBRARY: " + mesg.toString());
 100     }
 101 
 102     /**
 103      * Routines that enable rmi tests to fail in a uniformly
 104      * informative fashion.
 105      */
 106     public static void bomb(String message, Exception e) {
 107         String testFailed = "TEST FAILED: ";
 108 
 109         if ((message == null) && (e == null)) {
 110             testFailed += " No relevant information";
 111         } else if (e == null) {
 112             testFailed += message;
 113         }
 114 
 115         System.err.println(testFailed);
 116         if (e != null) {
 117             System.err.println("Test failed with: " +
 118                                e.getMessage());
 119             e.printStackTrace(System.err);
 120         }
 121         throw new TestFailedException(testFailed, e);
 122     }
 123     public static void bomb(String message) {
 124         bomb(message, null);
 125     }
 126     public static void bomb(Exception e) {
 127         bomb(null, e);
 128     }
 129 





















 130     public static String getProperty(String property, String defaultVal) {
 131         final String prop = property;
 132         final String def = defaultVal;
 133         return ((String) java.security.AccessController.doPrivileged
 134             (new java.security.PrivilegedAction<String>() {
 135                 public String run() {
 136                     return System.getProperty(prop, def);
 137                 }
 138             }));
 139     }
 140 
 141     /**
 142      * Property mutators
 143      */
 144     public static void setBoolean(String property, boolean value) {
 145         setProperty(property, (new Boolean(value)).toString());
 146     }
 147     public static void setInteger(String property, int value) {
 148         setProperty(property, Integer.toString(value));
 149     }
 150     public static void setProperty(String property, String value) {
 151         final String prop = property;
 152         final String val = value;
 153         java.security.AccessController.doPrivileged
 154             (new java.security.PrivilegedAction<Void>() {
 155                 public Void run() {
 156                     System.setProperty(prop, val);
 157                     return null;
 158                 }
 159         });
 160     }
 161 
 162     /**
 163      * Routines to print out a test's properties environment.
 164      */
 165     public static void printEnvironment() {
 166         printEnvironment(System.err);
 167     }
 168     public static void printEnvironment(PrintStream out) {
 169         out.println("-------------------Test environment----------" +
 170                     "---------");
 171 
 172         for(Enumeration<?> keys = System.getProperties().keys();
 173             keys.hasMoreElements();) {
 174 
 175             String property = (String) keys.nextElement();
 176             out.println(property + " = " + getProperty(property, null));
 177         }
 178         out.println("---------------------------------------------" +
 179                     "---------");
 180     }
 181 
 182     /**
 183      * Routine that "works-around" a limitation in jtreg.
 184      * Currently it is not possible for a test to specify that the
 185      * test harness should build a given source file and install the
 186      * resulting class in a location that is not accessible from the
 187      * test's classpath.  This method enables a test to move a
 188      * compiled test class file from the test's class directory into a
 189      * given "codebase" directory.  As a result the test can only
 190      * access the class file for <code>className</code>if the test loads
 191      * it from a classloader (e.g. RMIClassLoader).
 192      *


 216         String classFileName = className + ".class";
 217 
 218         /*
 219          * Specify the file to contain the class definition.  Make sure
 220          * that the codebase directory exists (underneath the working
 221          * directory).
 222          */
 223         File dstDir = (new File(getProperty("user.dir", "."), codebase));
 224 
 225         if (!dstDir.exists()) {
 226             if (!dstDir.mkdir()) {
 227                 throw new RuntimeException(
 228                     "could not create codebase directory");
 229             }
 230         }
 231         File dstFile = new File(dstDir, classFileName);
 232 
 233         /*
 234          * Obtain the URL for the codebase.
 235          */
 236         URL codebaseURL = dstDir.toURI().toURL();
 237 
 238         /*
 239          * Specify where we will copy the class definition from, if
 240          * necessary.  After the test is built, the class file can be
 241          * found in the "test.classes" directory.
 242          */
 243         File srcDir = new File(getProperty("test.classes", "."));
 244         File srcFile = new File(srcDir, classFileName);
 245 
 246         mesg(srcFile);
 247         mesg(dstFile);
 248 
 249         /*
 250          * If the class definition is not already located at the codebase,
 251          * copy it there from the test build area.
 252          */
 253         if (!dstFile.exists()) {
 254             if (!srcFile.exists()) {
 255                 throw new RuntimeException(
 256                     "could not find class file to install in codebase " +


 371             Endpoint endpoint = liveRef.getChannel().getEndpoint();
 372             TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint;
 373             port = tcpEndpoint.getPort();
 374         } catch (Exception ex) {
 375             throw new RuntimeException("Error getting registry port.", ex);
 376         }
 377 
 378         return port;
 379     }
 380 
 381     /**
 382      * Returns an unused random port number which is not a reserved port.  Will
 383      * try up to 10 times to get a random port before giving up and throwing a
 384      * RuntimeException.
 385      *
 386      * @return an unused random port number.
 387      * @throws RuntimeException if there was a problem getting a port.
 388      */
 389     public static int getUnusedRandomPort() {
 390         int numTries = 0;
 391         int unusedRandomPort = -1;
 392         IOException ex = null;
 393 
 394         while (numTries++ < MAX_SERVER_SOCKET_TRIES) {
 395             ex = null; //reset
 396 
 397             try (ServerSocket ss = new ServerSocket(0)) {
 398                 unusedRandomPort = ss.getLocalPort();
 399             } catch (IOException e) {
 400                 ex = e;
 401                 // temporarily print stack trace here until we find out why
 402                 // tests are failing.
 403                 System.err.println("TestLibrary.getUnusedRandomPort() caught "
 404                         + "exception on iteration " + numTries
 405                         + (numTries==MAX_SERVER_SOCKET_TRIES ? " (the final try)."
 406                         : "."));
 407                 ex.printStackTrace();
 408             }
 409 
 410             if (unusedRandomPort >= 0) {
 411                 if (isReservedPort(unusedRandomPort)) {
 412                     System.out.println("INFO: On try # " + numTries
 413                         + (numTries==MAX_SERVER_SOCKET_TRIES ? ", the final try, ": ",")
 414                         + " ServerSocket(0) returned the reserved port "
 415                         + unusedRandomPort
 416                         + " in TestLibrary.getUnusedRandomPort() ");
 417                 } else {
 418                     return unusedRandomPort;
 419                 }
 420             }
 421         }
 422 
 423         // If we're here, then either an exception was thrown or the port is
 424         // a reserved port.
 425         if (ex==null) {
 426             throw new RuntimeException("Error getting unused random port. The"
 427                     +" last port returned by ServerSocket(0) was a reserved port");
 428         } else {
 429             throw new RuntimeException("Error getting unused random port.", ex);
 430         }
 431     }
 432 
 433     /**
 434      * Determines if a port is one of the reserved port numbers.
 435      *
 436      * @param port the port to test.
 437      * @return {@code true} if the port is a reserved port, otherwise
 438      *         {@code false}.
 439      */
 440     public static boolean isReservedPort(int port) {
 441         return ((port >= FIXED_PORT_MIN) && (port <= FIXED_PORT_MAX) ||
 442                 (port == 1099));
 443     }
 444 
 445     /**
 446      * Method to capture the stack trace of an exception and return it
 447      * as a string.
 448      */
 449     public String stackTraceToString(Exception e) {
 450         ByteArrayOutputStream bos = new ByteArrayOutputStream();