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