1 /* 2 * Copyright (c) 1998, 2014, 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(final String property, 158 final String defaultVal) { 159 try { 160 return java.security.AccessController.doPrivileged( 161 new java.security.PrivilegedAction<String>() { 162 public String run() { 163 return System.getProperty(property, defaultVal); 164 } 165 }); 166 } catch (Exception ex) { 167 bomb("Exception getting property " + property, ex); 168 throw new AssertionError("this should be unreachable"); 169 } 170 } 171 172 /** 173 * Property mutators 174 */ 175 public static void setBoolean(String property, boolean value) { 176 setProperty(property, (new Boolean(value)).toString()); 177 } 178 public static void setInteger(String property, int value) { 179 setProperty(property, Integer.toString(value)); 180 } 181 public static void setProperty(String property, String value) { 182 final String prop = property; 183 final String val = value; 184 java.security.AccessController.doPrivileged( 185 new java.security.PrivilegedAction<Void>() { 186 public Void run() { 187 System.setProperty(prop, val); 188 return null; 189 } 190 }); 191 } 192 193 /** 194 * Routines to print out a test's properties environment. 195 */ 196 public static void printEnvironment() { 197 printEnvironment(System.err); 198 } 199 public static void printEnvironment(PrintStream out) { 200 out.println("-------------------Test environment----------" + 201 "---------"); 202 203 for(Enumeration<?> keys = System.getProperties().keys(); 204 keys.hasMoreElements();) { 205 206 String property = (String) keys.nextElement(); 207 out.println(property + " = " + getProperty(property, null)); 208 } 209 out.println("---------------------------------------------" + 210 "---------"); 211 } 212 213 /** 214 * Routine that "works-around" a limitation in jtreg. 215 * Currently it is not possible for a test to specify that the 216 * test harness should build a given source file and install the 217 * resulting class in a location that is not accessible from the 218 * test's classpath. This method enables a test to move a 219 * compiled test class file from the test's class directory into a 220 * given "codebase" directory. As a result the test can only 221 * access the class file for <code>className</code>if the test loads 222 * it from a classloader (e.g. RMIClassLoader). 223 * 224 * Tests that use this routine must have the following permissions 225 * granted to them: 226 * 227 * getProperty user.dir 228 * getProperty etc. 229 */ 230 public static URL installClassInCodebase(String className, 231 String codebase) 232 throws MalformedURLException 233 { 234 return installClassInCodebase(className, codebase, true); 235 } 236 237 public static URL installClassInCodebase(String className, 238 String codebase, 239 boolean delete) 240 throws MalformedURLException 241 { 242 /* 243 * NOTES/LIMITATIONS: The class must not be in a named package, 244 * and the codebase must be a relative path (it's created relative 245 * to the working directory). 246 */ 247 String classFileName = className + ".class"; 248 249 /* 250 * Specify the file to contain the class definition. Make sure 251 * that the codebase directory exists (underneath the working 252 * directory). 253 */ 254 File dstDir = (new File(getProperty("user.dir", "."), codebase)); 255 256 if (!dstDir.exists()) { 257 if (!dstDir.mkdir()) { 258 throw new RuntimeException( 259 "could not create codebase directory"); 260 } 261 } 262 File dstFile = new File(dstDir, classFileName); 263 264 /* 265 * Obtain the URL for the codebase. 266 */ 267 URL codebaseURL = dstDir.toURI().toURL(); 268 269 /* 270 * Specify where we will copy the class definition from, if 271 * necessary. After the test is built, the class file can be 272 * found in the "test.classes" directory. 273 */ 274 File srcDir = new File(getProperty("test.classes", ".")); 275 File srcFile = new File(srcDir, classFileName); 276 277 mesg(srcFile); 278 mesg(dstFile); 279 280 /* 281 * If the class definition is not already located at the codebase, 282 * copy it there from the test build area. 283 */ 284 if (!dstFile.exists()) { 285 if (!srcFile.exists()) { 286 throw new RuntimeException( 287 "could not find class file to install in codebase " + 288 "(try rebuilding the test): " + srcFile); 289 } 290 291 try { 292 copyFile(srcFile, dstFile); 293 } catch (IOException e) { 294 throw new RuntimeException( 295 "could not install class file in codebase"); 296 } 297 298 mesg("Installed class \"" + className + 299 "\" in codebase " + codebaseURL); 300 } 301 302 /* 303 * After the class definition is successfully installed at the 304 * codebase, delete it from the test's CLASSPATH, so that it will 305 * not be found there first before the codebase is searched. 306 */ 307 if (srcFile.exists()) { 308 if (delete && !srcFile.delete()) { 309 throw new RuntimeException( 310 "could not delete duplicate class file in CLASSPATH"); 311 } 312 } 313 314 return codebaseURL; 315 } 316 317 public static void copyFile(File srcFile, File dstFile) 318 throws IOException 319 { 320 FileInputStream src = new FileInputStream(srcFile); 321 FileOutputStream dst = new FileOutputStream(dstFile); 322 323 byte[] buf = new byte[32768]; 324 while (true) { 325 int count = src.read(buf); 326 if (count < 0) { 327 break; 328 } 329 dst.write(buf, 0, count); 330 } 331 332 dst.close(); 333 src.close(); 334 } 335 336 /** routine to unexport an object */ 337 public static void unexport(Remote obj) { 338 if (obj != null) { 339 try { 340 mesg("unexporting object..."); 341 UnicastRemoteObject.unexportObject(obj, true); 342 } catch (NoSuchObjectException munch) { 343 } catch (Exception e) { 344 e.getMessage(); 345 e.printStackTrace(); 346 } 347 } 348 } 349 350 /** 351 * Allow test framework to control the security manager set in 352 * each test. 353 * 354 * @param managerClassName The class name of the security manager 355 * to be instantiated and set if no security 356 * manager has already been set. 357 */ 358 public static void suggestSecurityManager(String managerClassName) { 359 SecurityManager manager = null; 360 361 if (System.getSecurityManager() == null) { 362 try { 363 if (managerClassName == null) { 364 managerClassName = TestParams.defaultSecurityManager; 365 } 366 manager = ((SecurityManager) Class. 367 forName(managerClassName).newInstance()); 368 } catch (ClassNotFoundException cnfe) { 369 bomb("Security manager could not be found: " + 370 managerClassName, cnfe); 371 } catch (Exception e) { 372 bomb("Error creating security manager. ", e); 373 } 374 375 System.setSecurityManager(manager); 376 } 377 } 378 379 /** 380 * Creates an RMI {@link Registry} on a random, un-reserved port. 381 * 382 * @returns an RMI Registry, using a random port. 383 * @throws RemoteException if there was a problem creating a Registry. 384 */ 385 public static Registry createRegistryOnUnusedPort() throws RemoteException { 386 return LocateRegistry.createRegistry(getUnusedRandomPort()); 387 } 388 389 /** 390 * Returns the port number the RMI {@link Registry} is running on. 391 * 392 * @param registry the registry to find the port of. 393 * @return the port number the registry is using. 394 * @throws RuntimeException if there was a problem getting the port number. 395 */ 396 public static int getRegistryPort(Registry registry) { 397 int port = -1; 398 399 try { 400 RemoteRef remoteRef = ((RegistryImpl)registry).getRef(); 401 LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef(); 402 Endpoint endpoint = liveRef.getChannel().getEndpoint(); 403 TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint; 404 port = tcpEndpoint.getPort(); 405 } catch (Exception ex) { 406 throw new RuntimeException("Error getting registry port.", ex); 407 } 408 409 return port; 410 } 411 412 /** 413 * Returns an unused random port number which is not a reserved port. Will 414 * try up to 10 times to get a random port before giving up and throwing a 415 * RuntimeException. 416 * 417 * @return an unused random port number. 418 * @throws RuntimeException if there was a problem getting a port. 419 */ 420 public static int getUnusedRandomPort() { 421 int numTries = 0; 422 IOException ex = null; 423 424 while (numTries++ < MAX_SERVER_SOCKET_TRIES) { 425 int unusedRandomPort = -1; 426 ex = null; //reset 427 428 try (ServerSocket ss = new ServerSocket(0)) { 429 unusedRandomPort = ss.getLocalPort(); 430 } catch (IOException e) { 431 ex = e; 432 // temporarily print stack trace here until we find out why 433 // tests are failing. 434 System.err.println("TestLibrary.getUnusedRandomPort() caught " 435 + "exception on iteration " + numTries 436 + (numTries==MAX_SERVER_SOCKET_TRIES ? " (the final try)." 437 : ".")); 438 ex.printStackTrace(); 439 } 440 441 if (unusedRandomPort >= 0) { 442 if (isReservedPort(unusedRandomPort)) { 443 System.out.println("INFO: On try # " + numTries 444 + (numTries==MAX_SERVER_SOCKET_TRIES ? ", the final try, ": ",") 445 + " ServerSocket(0) returned the reserved port " 446 + unusedRandomPort 447 + " in TestLibrary.getUnusedRandomPort() "); 448 } else { 449 return unusedRandomPort; 450 } 451 } 452 } 453 454 // If we're here, then either an exception was thrown or the port is 455 // a reserved port. 456 if (ex==null) { 457 throw new RuntimeException("Error getting unused random port. The" 458 +" last port returned by ServerSocket(0) was a reserved port"); 459 } else { 460 throw new RuntimeException("Error getting unused random port.", ex); 461 } 462 } 463 464 /** 465 * Determines if a port is one of the reserved port numbers. 466 * 467 * @param port the port to test. 468 * @return {@code true} if the port is a reserved port, otherwise 469 * {@code false}. 470 */ 471 public static boolean isReservedPort(int port) { 472 return ((port >= FIXED_PORT_MIN) && (port <= FIXED_PORT_MAX) || 473 (port == 1099)); 474 } 475 476 /** 477 * Method to capture the stack trace of an exception and return it 478 * as a string. 479 */ 480 public String stackTraceToString(Exception e) { 481 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 482 PrintStream ps = new PrintStream(bos); 483 484 e.printStackTrace(ps); 485 return bos.toString(); 486 } 487 488 /** extra properties */ 489 private static Properties props; 490 491 /** 492 * Returns extra test properties. Looks for the file "../../test.props" 493 * and reads it in as a Properties file. Assuming the working directory 494 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 495 */ 496 private static synchronized Properties getExtraProperties() { 497 if (props != null) { 498 return props; 499 } 500 props = new Properties(); 501 File f = new File(".." + File.separator + ".." + File.separator + 502 "test.props"); 503 if (!f.exists()) { 504 return props; 505 } 506 try { 507 FileInputStream in = new FileInputStream(f); 508 try { 509 props.load(in); 510 } finally { 511 in.close(); 512 } 513 } catch (IOException e) { 514 e.printStackTrace(); 515 throw new RuntimeException("extra property setup failed", e); 516 } 517 return props; 518 } 519 520 /** 521 * Returns an extra test property. Looks for the file "../../test.props" 522 * and reads it in as a Properties file. Assuming the working directory 523 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 524 * If the property isn't found, defaultVal is returned. 525 */ 526 public static String getExtraProperty(String property, String defaultVal) { 527 return getExtraProperties().getProperty(property, defaultVal); 528 } 529 }