1 /* 2 * Copyright (c) 1998, 2012, 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 = 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 * 193 * Tests that use this routine must have the following permissions 194 * granted to them: 195 * 196 * getProperty user.dir 197 * getProperty etc. 198 */ 199 public static URL installClassInCodebase(String className, 200 String codebase) 201 throws MalformedURLException 202 { 203 return installClassInCodebase(className, codebase, true); 204 } 205 206 public static URL installClassInCodebase(String className, 207 String codebase, 208 boolean delete) 209 throws MalformedURLException 210 { 211 /* 212 * NOTES/LIMITATIONS: The class must not be in a named package, 213 * and the codebase must be a relative path (it's created relative 214 * to the working directory). 215 */ 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 " + 257 "(try rebuilding the test): " + srcFile); 258 } 259 260 try { 261 copyFile(srcFile, dstFile); 262 } catch (IOException e) { 263 throw new RuntimeException( 264 "could not install class file in codebase"); 265 } 266 267 mesg("Installed class \"" + className + 268 "\" in codebase " + codebaseURL); 269 } 270 271 /* 272 * After the class definition is successfully installed at the 273 * codebase, delete it from the test's CLASSPATH, so that it will 274 * not be found there first before the codebase is searched. 275 */ 276 if (srcFile.exists()) { 277 if (delete && !srcFile.delete()) { 278 throw new RuntimeException( 279 "could not delete duplicate class file in CLASSPATH"); 280 } 281 } 282 283 return codebaseURL; 284 } 285 286 public static void copyFile(File srcFile, File dstFile) 287 throws IOException 288 { 289 FileInputStream src = new FileInputStream(srcFile); 290 FileOutputStream dst = new FileOutputStream(dstFile); 291 292 byte[] buf = new byte[32768]; 293 while (true) { 294 int count = src.read(buf); 295 if (count < 0) { 296 break; 297 } 298 dst.write(buf, 0, count); 299 } 300 301 dst.close(); 302 src.close(); 303 } 304 305 /** routine to unexport an object */ 306 public static void unexport(Remote obj) { 307 if (obj != null) { 308 try { 309 mesg("unexporting object..."); 310 UnicastRemoteObject.unexportObject(obj, true); 311 } catch (NoSuchObjectException munch) { 312 } catch (Exception e) { 313 e.getMessage(); 314 e.printStackTrace(); 315 } 316 } 317 } 318 319 /** 320 * Allow test framework to control the security manager set in 321 * each test. 322 * 323 * @param managerClassName The class name of the security manager 324 * to be instantiated and set if no security 325 * manager has already been set. 326 */ 327 public static void suggestSecurityManager(String managerClassName) { 328 SecurityManager manager = null; 329 330 if (System.getSecurityManager() == null) { 331 try { 332 if (managerClassName == null) { 333 managerClassName = TestParams.defaultSecurityManager; 334 } 335 manager = ((SecurityManager) Class. 336 forName(managerClassName).newInstance()); 337 } catch (ClassNotFoundException cnfe) { 338 bomb("Security manager could not be found: " + 339 managerClassName, cnfe); 340 } catch (Exception e) { 341 bomb("Error creating security manager. ", e); 342 } 343 344 System.setSecurityManager(manager); 345 } 346 } 347 348 /** 349 * Creates an RMI {@link Registry} on a random, un-reserved port. 350 * 351 * @returns an RMI Registry, using a random port. 352 * @throws RemoteException if there was a problem creating a Registry. 353 */ 354 public static Registry createRegistryOnUnusedPort() throws RemoteException { 355 return LocateRegistry.createRegistry(getUnusedRandomPort()); 356 } 357 358 /** 359 * Returns the port number the RMI {@link Registry} is running on. 360 * 361 * @param registry the registry to find the port of. 362 * @return the port number the registry is using. 363 * @throws RuntimeException if there was a problem getting the port number. 364 */ 365 public static int getRegistryPort(Registry registry) { 366 int port = -1; 367 368 try { 369 RemoteRef remoteRef = ((RegistryImpl)registry).getRef(); 370 LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef(); 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(); 451 PrintStream ps = new PrintStream(bos); 452 453 e.printStackTrace(ps); 454 return bos.toString(); 455 } 456 457 /** extra properties */ 458 private static Properties props; 459 460 /** 461 * Returns extra test properties. Looks for the file "../../test.props" 462 * and reads it in as a Properties file. Assuming the working directory 463 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 464 */ 465 private static synchronized Properties getExtraProperties() { 466 if (props != null) { 467 return props; 468 } 469 props = new Properties(); 470 File f = new File(".." + File.separator + ".." + File.separator + 471 "test.props"); 472 if (!f.exists()) { 473 return props; 474 } 475 try { 476 FileInputStream in = new FileInputStream(f); 477 try { 478 props.load(in); 479 } finally { 480 in.close(); 481 } 482 } catch (IOException e) { 483 e.printStackTrace(); 484 throw new RuntimeException("extra property setup failed", e); 485 } 486 return props; 487 } 488 489 /** 490 * Returns an extra test property. Looks for the file "../../test.props" 491 * and reads it in as a Properties file. Assuming the working directory 492 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 493 * If the property isn't found, defaultVal is returned. 494 */ 495 public static String getExtraProperty(String property, String defaultVal) { 496 return getExtraProperties().getProperty(property, defaultVal); 497 } 498 }