1 /*
   2  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  *
  26  *
  27  * @author Adrian Colley
  28  * @author Laird Dornin
  29  * @author Peter Jones
  30  * @author Ann Wollrath
  31  *
  32  * The rmi library directory contains a set of simple utiltity classes
  33  * for use in rmi regression tests.
  34  *
  35  * NOTE: The JavaTest group has recommended that regression tests do
  36  * not make use of packages.
  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 = 60001;
  90     public final static int FIXED_PORT_MAX = 60010;
  91     public final static int RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT = 60001;
  92     public final static int RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT = 60002;
  93     public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 60003;
  94     public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 60004;
  95     public final static int READTEST_REGISTRY_PORT = 60005;
  96     private final static int MAX_SERVER_SOCKET_TRIES = 2*(FIXED_PORT_MAX-FIXED_PORT_MIN+1);
  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     /**
 131      * Helper method to determine if registry has started
 132      *
 133      * @param port The port number to check
 134      * @param msTimeout The amount of milliseconds to spend checking
 135      */
 136 
 137     public static boolean checkIfRegistryRunning(int port, int msTimeout) {
 138         long stopTime = System.currentTimeMillis() + msTimeout;
 139         do {
 140             try {
 141                 Registry r = LocateRegistry.getRegistry(port);
 142                 String[] s = r.list();
 143                 // no exception. We're now happy that registry is running
 144                 return true;
 145             } catch (RemoteException e) {
 146                 // problem - not ready ? Try again
 147                 try {
 148                     Thread.sleep(500);
 149                 } catch (InterruptedException ie) {
 150                     // not expected
 151                 }
 152             }
 153         } while (stopTime > System.currentTimeMillis());
 154         return false;
 155     }
 156 
 157     public static String getProperty(String property, String defaultVal) {
 158         final String prop = property;
 159         final String def = defaultVal;
 160         return java.security.AccessController.doPrivileged(
 161             new java.security.PrivilegedAction<String>() {
 162                 public String run() {
 163                     return System.getProperty(prop, def);
 164                 }
 165             });
 166     }
 167 
 168     /**
 169      * Property mutators
 170      */
 171     public static void setBoolean(String property, boolean value) {
 172         setProperty(property, (new Boolean(value)).toString());
 173     }
 174     public static void setInteger(String property, int value) {
 175         setProperty(property, Integer.toString(value));
 176     }
 177     public static void setProperty(String property, String value) {
 178         final String prop = property;
 179         final String val = value;
 180         java.security.AccessController.doPrivileged(
 181             new java.security.PrivilegedAction<Void>() {
 182                 public Void run() {
 183                     System.setProperty(prop, val);
 184                     return null;
 185                 }
 186         });
 187     }
 188 
 189     /**
 190      * Routines to print out a test's properties environment.
 191      */
 192     public static void printEnvironment() {
 193         printEnvironment(System.err);
 194     }
 195     public static void printEnvironment(PrintStream out) {
 196         out.println("-------------------Test environment----------" +
 197                     "---------");
 198 
 199         for(Enumeration<?> keys = System.getProperties().keys();
 200             keys.hasMoreElements();) {
 201 
 202             String property = (String) keys.nextElement();
 203             out.println(property + " = " + getProperty(property, null));
 204         }
 205         out.println("---------------------------------------------" +
 206                     "---------");
 207     }
 208 
 209     /**
 210      * Routine that "works-around" a limitation in jtreg.
 211      * Currently it is not possible for a test to specify that the
 212      * test harness should build a given source file and install the
 213      * resulting class in a location that is not accessible from the
 214      * test's classpath.  This method enables a test to move a
 215      * compiled test class file from the test's class directory into a
 216      * given "codebase" directory.  As a result the test can only
 217      * access the class file for <code>className</code>if the test loads
 218      * it from a classloader (e.g. RMIClassLoader).
 219      *
 220      * Tests that use this routine must have the following permissions
 221      * granted to them:
 222      *
 223      *   getProperty user.dir
 224      *   getProperty etc.
 225      */
 226     public static URL installClassInCodebase(String className,
 227                                              String codebase)
 228         throws MalformedURLException
 229     {
 230         return installClassInCodebase(className, codebase, true);
 231     }
 232 
 233     public static URL installClassInCodebase(String className,
 234                                              String codebase,
 235                                              boolean delete)
 236         throws MalformedURLException
 237     {
 238         /*
 239          * NOTES/LIMITATIONS: The class must not be in a named package,
 240          * and the codebase must be a relative path (it's created relative
 241          * to the working directory).
 242          */
 243         String classFileName = className + ".class";
 244 
 245         /*
 246          * Specify the file to contain the class definition.  Make sure
 247          * that the codebase directory exists (underneath the working
 248          * directory).
 249          */
 250         File dstDir = (new File(getProperty("user.dir", "."), codebase));
 251 
 252         if (!dstDir.exists()) {
 253             if (!dstDir.mkdir()) {
 254                 throw new RuntimeException(
 255                     "could not create codebase directory");
 256             }
 257         }
 258         File dstFile = new File(dstDir, classFileName);
 259 
 260         /*
 261          * Obtain the URL for the codebase.
 262          */
 263         URL codebaseURL = dstDir.toURI().toURL();
 264 
 265         /*
 266          * Specify where we will copy the class definition from, if
 267          * necessary.  After the test is built, the class file can be
 268          * found in the "test.classes" directory.
 269          */
 270         File srcDir = new File(getProperty("test.classes", "."));
 271         File srcFile = new File(srcDir, classFileName);
 272 
 273         mesg(srcFile);
 274         mesg(dstFile);
 275 
 276         /*
 277          * If the class definition is not already located at the codebase,
 278          * copy it there from the test build area.
 279          */
 280         if (!dstFile.exists()) {
 281             if (!srcFile.exists()) {
 282                 throw new RuntimeException(
 283                     "could not find class file to install in codebase " +
 284                     "(try rebuilding the test): " + srcFile);
 285             }
 286 
 287             try {
 288                 copyFile(srcFile, dstFile);
 289             } catch (IOException e) {
 290                 throw new RuntimeException(
 291                     "could not install class file in codebase");
 292             }
 293 
 294             mesg("Installed class \"" + className +
 295                 "\" in codebase " + codebaseURL);
 296         }
 297 
 298         /*
 299          * After the class definition is successfully installed at the
 300          * codebase, delete it from the test's CLASSPATH, so that it will
 301          * not be found there first before the codebase is searched.
 302          */
 303         if (srcFile.exists()) {
 304             if (delete && !srcFile.delete()) {
 305                 throw new RuntimeException(
 306                     "could not delete duplicate class file in CLASSPATH");
 307             }
 308         }
 309 
 310         return codebaseURL;
 311     }
 312 
 313     public static void copyFile(File srcFile, File dstFile)
 314         throws IOException
 315     {
 316         FileInputStream src = new FileInputStream(srcFile);
 317         FileOutputStream dst = new FileOutputStream(dstFile);
 318 
 319         byte[] buf = new byte[32768];
 320         while (true) {
 321             int count = src.read(buf);
 322             if (count < 0) {
 323                 break;
 324             }
 325             dst.write(buf, 0, count);
 326         }
 327 
 328         dst.close();
 329         src.close();
 330     }
 331 
 332     /** routine to unexport an object */
 333     public static void unexport(Remote obj) {
 334         if (obj != null) {
 335             try {
 336                 mesg("unexporting object...");
 337                 UnicastRemoteObject.unexportObject(obj, true);
 338             } catch (NoSuchObjectException munch) {
 339             } catch (Exception e) {
 340                 e.getMessage();
 341                 e.printStackTrace();
 342             }
 343         }
 344     }
 345 
 346     /**
 347      * Allow test framework to control the security manager set in
 348      * each test.
 349      *
 350      * @param managerClassName The class name of the security manager
 351      *                         to be instantiated and set if no security
 352      *                         manager has already been set.
 353      */
 354     public static void suggestSecurityManager(String managerClassName) {
 355         SecurityManager manager = null;
 356 
 357         if (System.getSecurityManager() == null) {
 358             try {
 359                 if (managerClassName == null) {
 360                     managerClassName = TestParams.defaultSecurityManager;
 361                 }
 362                 manager = ((SecurityManager) Class.
 363                            forName(managerClassName).newInstance());
 364             } catch (ClassNotFoundException cnfe) {
 365                 bomb("Security manager could not be found: " +
 366                      managerClassName, cnfe);
 367             } catch (Exception e) {
 368                 bomb("Error creating security manager. ", e);
 369             }
 370 
 371             System.setSecurityManager(manager);
 372         }
 373     }
 374 
 375     /**
 376      * Creates an RMI {@link Registry} on a random, un-reserved port.
 377      *
 378      * @returns an RMI Registry, using a random port.
 379      * @throws RemoteException if there was a problem creating a Registry.
 380      */
 381     public static Registry createRegistryOnUnusedPort() throws RemoteException {
 382         return LocateRegistry.createRegistry(getUnusedRandomPort());
 383     }
 384 
 385     /**
 386      * Returns the port number the RMI {@link Registry} is running on.
 387      *
 388      * @param registry the registry to find the port of.
 389      * @return the port number the registry is using.
 390      * @throws RuntimeException if there was a problem getting the port number.
 391      */
 392     public static int getRegistryPort(Registry registry) {
 393         int port = -1;
 394 
 395         try {
 396             RemoteRef remoteRef = ((RegistryImpl)registry).getRef();
 397             LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef();
 398             Endpoint endpoint = liveRef.getChannel().getEndpoint();
 399             TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint;
 400             port = tcpEndpoint.getPort();
 401         } catch (Exception ex) {
 402             throw new RuntimeException("Error getting registry port.", ex);
 403         }
 404 
 405         return port;
 406     }
 407 
 408     /**
 409      * Returns an unused random port number which is not a reserved port.  Will
 410      * try up to 10 times to get a random port before giving up and throwing a
 411      * RuntimeException.
 412      *
 413      * @return an unused random port number.
 414      * @throws RuntimeException if there was a problem getting a port.
 415      */
 416     public static int getUnusedRandomPort() {
 417         int numTries = 0;
 418         IOException ex = null;
 419 
 420         while (numTries++ < MAX_SERVER_SOCKET_TRIES) {
 421             int unusedRandomPort = -1;
 422             ex = null; //reset
 423 
 424             try (ServerSocket ss = new ServerSocket(0)) {
 425                 unusedRandomPort = ss.getLocalPort();
 426             } catch (IOException e) {
 427                 ex = e;
 428                 // temporarily print stack trace here until we find out why
 429                 // tests are failing.
 430                 System.err.println("TestLibrary.getUnusedRandomPort() caught "
 431                         + "exception on iteration " + numTries
 432                         + (numTries==MAX_SERVER_SOCKET_TRIES ? " (the final try)."
 433                         : "."));
 434                 ex.printStackTrace();
 435             }
 436 
 437             if (unusedRandomPort >= 0) {
 438                 if (isReservedPort(unusedRandomPort)) {
 439                     System.out.println("INFO: On try # " + numTries
 440                         + (numTries==MAX_SERVER_SOCKET_TRIES ? ", the final try, ": ",")
 441                         + " ServerSocket(0) returned the reserved port "
 442                         + unusedRandomPort
 443                         + " in TestLibrary.getUnusedRandomPort() ");
 444                 } else {
 445                     return unusedRandomPort;
 446                 }
 447             }
 448         }
 449 
 450         // If we're here, then either an exception was thrown or the port is
 451         // a reserved port.
 452         if (ex==null) {
 453             throw new RuntimeException("Error getting unused random port. The"
 454                     +" last port returned by ServerSocket(0) was a reserved port");
 455         } else {
 456             throw new RuntimeException("Error getting unused random port.", ex);
 457         }
 458     }
 459 
 460     /**
 461      * Determines if a port is one of the reserved port numbers.
 462      *
 463      * @param port the port to test.
 464      * @return {@code true} if the port is a reserved port, otherwise
 465      *         {@code false}.
 466      */
 467     public static boolean isReservedPort(int port) {
 468         return ((port >= FIXED_PORT_MIN) && (port <= FIXED_PORT_MAX) ||
 469                 (port == 1099));
 470     }
 471 
 472     /**
 473      * Method to capture the stack trace of an exception and return it
 474      * as a string.
 475      */
 476     public String stackTraceToString(Exception e) {
 477         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 478         PrintStream ps = new PrintStream(bos);
 479 
 480         e.printStackTrace(ps);
 481         return bos.toString();
 482     }
 483 
 484     /** extra properties */
 485     private static Properties props;
 486 
 487     /**
 488      * Returns extra test properties. Looks for the file "../../test.props"
 489      * and reads it in as a Properties file. Assuming the working directory
 490      * is "<path>/JTwork/scratch", this will find "<path>/test.props".
 491      */
 492     private static synchronized Properties getExtraProperties() {
 493         if (props != null) {
 494             return props;
 495         }
 496         props = new Properties();
 497         File f = new File(".." + File.separator + ".." + File.separator +
 498                           "test.props");
 499         if (!f.exists()) {
 500             return props;
 501         }
 502         try {
 503             FileInputStream in = new FileInputStream(f);
 504             try {
 505                 props.load(in);
 506             } finally {
 507                 in.close();
 508             }
 509         } catch (IOException e) {
 510             e.printStackTrace();
 511             throw new RuntimeException("extra property setup failed", e);
 512         }
 513         return props;
 514     }
 515 
 516     /**
 517      * Returns an extra test property. Looks for the file "../../test.props"
 518      * and reads it in as a Properties file. Assuming the working directory
 519      * is "<path>/JTwork/scratch", this will find "<path>/test.props".
 520      * If the property isn't found, defaultVal is returned.
 521      */
 522     public static String getExtraProperty(String property, String defaultVal) {
 523         return getExtraProperties().getProperty(property, defaultVal);
 524     }
 525 }