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