1 /* 2 * Copyright (c) 1998, 2003, 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.File; 40 import java.io.FileInputStream; 41 import java.io.FileOutputStream; 42 import java.io.IOException; 43 import java.io.PrintStream; 44 import java.net.URL; 45 import java.net.MalformedURLException; 46 import java.net.ServerSocket; 47 import java.rmi.NoSuchObjectException; 48 import java.rmi.registry.Registry; 49 import java.rmi.Remote; 50 import java.rmi.server.UnicastRemoteObject; 51 import java.util.Enumeration; 52 import java.util.Properties; 53 import java.io.ByteArrayOutputStream; 54 import java.rmi.RemoteException; 55 import java.rmi.registry.LocateRegistry; 56 import java.rmi.server.RemoteRef; 57 import sun.rmi.registry.RegistryImpl; 58 import sun.rmi.server.UnicastServerRef; 59 import sun.rmi.transport.Endpoint; 60 import sun.rmi.transport.LiveRef; 61 import sun.rmi.transport.tcp.TCPEndpoint; 62 63 /** 64 * Class of utility/library methods (i.e. procedures) that assist with 65 * the writing and maintainance of rmi regression tests. 66 */ 67 public class TestLibrary { 68 /** 69 * IMPORTANT! 70 * 71 * RMI tests are run concurrently and port conflicts result when a single 72 * port number is used by multiple tests for the RMI registry. Use 73 * getUnusedRandomPort() wherever possible. If getUnusedRandomPort() cannot 74 * be used, specify a port to use for the RMI registry for your test here. 75 * This will ensure there are no port conflicts amongst the RMI tests. The 76 * port numbers specified here may also be specified in the respective 77 * tests. Do not change these port numbers without also changing the port 78 * numbers in the respective tests. 79 * 80 * Reserve port range: 64001-64100 for tests which cannot use a random 81 * port. 82 */ 83 public final static int PORT_MIN = 1024; 84 public final static int PORT_MAX = 64000; 85 public final static int RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT = 64001; 86 public final static int RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT = 64002; 87 public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 64003; 88 public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 64004; 89 public final static int READTEST_REGISTRY_PORT = 64005; 90 91 static void mesg(Object mesg) { 92 System.err.println("TEST_LIBRARY: " + mesg.toString()); 93 } 94 95 /** 96 * Routines that enable rmi tests to fail in a uniformly 97 * informative fashion. 98 */ 99 public static void bomb(String message, Exception e) { 100 String testFailed = "TEST FAILED: "; 101 102 if ((message == null) && (e == null)) { 103 testFailed += " No relevant information"; 104 } else if (e == null) { 105 testFailed += message; 106 } 107 108 System.err.println(testFailed); 109 if (e != null) { 110 System.err.println("Test failed with: " + 111 e.getMessage()); 112 e.printStackTrace(System.err); 113 } 114 throw new TestFailedException(testFailed, e); 115 } 116 public static void bomb(String message) { 117 bomb(message, null); 118 } 119 public static void bomb(Exception e) { 120 bomb(null, e); 121 } 122 123 /** 124 * Property accessors 125 */ 126 private static boolean getBoolean(String name) { 127 return (new Boolean(getProperty(name, "false")).booleanValue()); 128 } 129 private static Integer getInteger(String name) { 130 int val = 0; 131 Integer value = null; 132 133 String propVal = getProperty(name, null); 134 if (propVal == null) { 135 return null; 136 } 137 138 try { 139 value = new Integer(Integer.parseInt(propVal)); 140 } catch (NumberFormatException nfe) { 141 } 142 return value; 143 } 144 public static String getProperty(String property, String defaultVal) { 145 final String prop = property; 146 final String def = defaultVal; 147 return ((String) java.security.AccessController.doPrivileged 148 (new java.security.PrivilegedAction() { 149 public Object run() { 150 return System.getProperty(prop, def); 151 } 152 })); 153 } 154 155 /** 156 * Property mutators 157 */ 158 public static void setBoolean(String property, boolean value) { 159 setProperty(property, (new Boolean(value)).toString()); 160 } 161 public static void setInteger(String property, int value) { 162 setProperty(property, Integer.toString(value)); 163 } 164 public static void setProperty(String property, String value) { 165 final String prop = property; 166 final String val = value; 167 java.security.AccessController.doPrivileged 168 (new java.security.PrivilegedAction() { 169 public Object run() { 170 System.setProperty(prop, val); 171 return null; 172 } 173 }); 174 } 175 176 /** 177 * Routines to print out a test's properties environment. 178 */ 179 public static void printEnvironment() { 180 printEnvironment(System.err); 181 } 182 public static void printEnvironment(PrintStream out) { 183 out.println("-------------------Test environment----------" + 184 "---------"); 185 186 for(Enumeration keys = System.getProperties().keys(); 187 keys.hasMoreElements();) { 188 189 String property = (String) keys.nextElement(); 190 out.println(property + " = " + getProperty(property, null)); 191 } 192 out.println("---------------------------------------------" + 193 "---------"); 194 } 195 196 /** 197 * Routine that "works-around" a limitation in jtreg. 198 * Currently it is not possible for a test to specify that the 199 * test harness should build a given source file and install the 200 * resulting class in a location that is not accessible from the 201 * test's classpath. This method enables a test to move a 202 * compiled test class file from the test's class directory into a 203 * given "codebase" directory. As a result the test can only 204 * access the class file for <code>className</code>if the test loads 205 * it from a classloader (e.g. RMIClassLoader). 206 * 207 * Tests that use this routine must have the following permissions 208 * granted to them: 209 * 210 * getProperty user.dir 211 * getProperty etc. 212 */ 213 public static URL installClassInCodebase(String className, 214 String codebase) 215 throws MalformedURLException 216 { 217 return installClassInCodebase(className, codebase, true); 218 } 219 220 public static URL installClassInCodebase(String className, 221 String codebase, 222 boolean delete) 223 throws MalformedURLException 224 { 225 /* 226 * NOTES/LIMITATIONS: The class must not be in a named package, 227 * and the codebase must be a relative path (it's created relative 228 * to the working directory). 229 */ 230 String classFileName = className + ".class"; 231 232 /* 233 * Specify the file to contain the class definition. Make sure 234 * that the codebase directory exists (underneath the working 235 * directory). 236 */ 237 File dstDir = (new File(getProperty("user.dir", "."), codebase)); 238 239 if (!dstDir.exists()) { 240 if (!dstDir.mkdir()) { 241 throw new RuntimeException( 242 "could not create codebase directory"); 243 } 244 } 245 File dstFile = new File(dstDir, classFileName); 246 247 /* 248 * Obtain the URL for the codebase. 249 */ 250 URL codebaseURL = dstDir.toURL(); 251 252 /* 253 * Specify where we will copy the class definition from, if 254 * necessary. After the test is built, the class file can be 255 * found in the "test.classes" directory. 256 */ 257 File srcDir = new File(getProperty("test.classes", ".")); 258 File srcFile = new File(srcDir, classFileName); 259 260 mesg(srcFile); 261 mesg(dstFile); 262 263 /* 264 * If the class definition is not already located at the codebase, 265 * copy it there from the test build area. 266 */ 267 if (!dstFile.exists()) { 268 if (!srcFile.exists()) { 269 throw new RuntimeException( 270 "could not find class file to install in codebase " + 271 "(try rebuilding the test): " + srcFile); 272 } 273 274 try { 275 copyFile(srcFile, dstFile); 276 } catch (IOException e) { 277 throw new RuntimeException( 278 "could not install class file in codebase"); 279 } 280 281 mesg("Installed class \"" + className + 282 "\" in codebase " + codebaseURL); 283 } 284 285 /* 286 * After the class definition is successfully installed at the 287 * codebase, delete it from the test's CLASSPATH, so that it will 288 * not be found there first before the codebase is searched. 289 */ 290 if (srcFile.exists()) { 291 if (delete && !srcFile.delete()) { 292 throw new RuntimeException( 293 "could not delete duplicate class file in CLASSPATH"); 294 } 295 } 296 297 return codebaseURL; 298 } 299 300 public static void copyFile(File srcFile, File dstFile) 301 throws IOException 302 { 303 FileInputStream src = new FileInputStream(srcFile); 304 FileOutputStream dst = new FileOutputStream(dstFile); 305 306 byte[] buf = new byte[32768]; 307 while (true) { 308 int count = src.read(buf); 309 if (count < 0) { 310 break; 311 } 312 dst.write(buf, 0, count); 313 } 314 315 dst.close(); 316 src.close(); 317 } 318 319 /** routine to unexport an object */ 320 public static void unexport(Remote obj) { 321 if (obj != null) { 322 try { 323 mesg("unexporting object..."); 324 UnicastRemoteObject.unexportObject(obj, true); 325 } catch (NoSuchObjectException munch) { 326 } catch (Exception e) { 327 e.getMessage(); 328 e.printStackTrace(); 329 } 330 } 331 } 332 333 /** 334 * Allow test framework to control the security manager set in 335 * each test. 336 * 337 * @param managerClassName The class name of the security manager 338 * to be instantiated and set if no security 339 * manager has already been set. 340 */ 341 public static void suggestSecurityManager(String managerClassName) { 342 SecurityManager manager = null; 343 344 if (System.getSecurityManager() == null) { 345 try { 346 if (managerClassName == null) { 347 managerClassName = TestParams.defaultSecurityManager; 348 } 349 manager = ((SecurityManager) Class. 350 forName(managerClassName).newInstance()); 351 } catch (ClassNotFoundException cnfe) { 352 bomb("Security manager could not be found: " + 353 managerClassName, cnfe); 354 } catch (Exception e) { 355 bomb("Error creating security manager. ", e); 356 } 357 358 System.setSecurityManager(manager); 359 } 360 } 361 362 /** 363 * Creates an RMI Registry on a random port. Tries up to 10 times before 364 * giving up and returning null. 365 * 366 * Note: if this method is called multiple times within a single VM, it will 367 * throw an exception. 368 * 369 * @returns a registry, started on a random port, or {@code null} if one 370 * could not be started. 371 */ 372 public static Registry createRegistryOnUnusedPort() throws RemoteException { 373 Registry registry = null; 374 int numTries = 0; 375 376 while ((numTries++ < 10) && (registry == null)) { 377 try { 378 registry = LocateRegistry.createRegistry(0); 379 } catch (RemoteException e) { 380 // Do nothing 381 } 382 } 383 384 return registry; 385 } 386 387 /** 388 * Returns the port number the RMI Registry is running on, or -1 if it could 389 * not be determined. 390 * 391 * @param registry the registry to find the port of. 392 * @return the port number the registry is using, or -1 if it could not be 393 * determined. 394 */ 395 public static int getRegistryPort(Registry registry) { 396 int port = -1; 397 398 try { 399 RemoteRef remoteRef = ((RegistryImpl)registry).getRef(); 400 LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef(); 401 Endpoint endpoint = liveRef.getChannel().getEndpoint(); 402 TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint; 403 port = tcpEndpoint.getPort(); 404 } catch (Exception ex) { 405 ex.printStackTrace(System.err); 406 } 407 408 return port; 409 } 410 411 /** 412 * Returns an unused random port number greater then or equal to PORT_MIN 413 * and less then or equal to PORT_MAX. Will try up to 10 times to get a 414 * random port before giving up and returning -1. 415 * 416 * @return an unused random port number, or -1. 417 */ 418 public static int getUnusedRandomPort() { 419 int numTries = 0; 420 int unusedRandomPort = -1; 421 422 while ((numTries++ < 10) && ((unusedRandomPort < PORT_MIN) || 423 (unusedRandomPort > PORT_MAX))) 424 { 425 try (ServerSocket ss = new ServerSocket(0)) { 426 unusedRandomPort = ss.getLocalPort(); 427 } catch (Exception e) { 428 // Do nothing 429 e.printStackTrace(); //djm 430 } 431 } 432 433 return unusedRandomPort; 434 } 435 436 /** 437 * Method to capture the stack trace of an exception and return it 438 * as a string. 439 */ 440 public String stackTraceToString(Exception e) { 441 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 442 PrintStream ps = new PrintStream(bos); 443 444 e.printStackTrace(ps); 445 return bos.toString(); 446 } 447 448 /** extra properties */ 449 private static Properties props; 450 451 /** 452 * Returns extra test properties. Looks for the file "../../test.props" 453 * and reads it in as a Properties file. Assuming the working directory 454 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 455 */ 456 private static synchronized Properties getExtraProperties() { 457 if (props != null) { 458 return props; 459 } 460 props = new Properties(); 461 File f = new File(".." + File.separator + ".." + File.separator + 462 "test.props"); 463 if (!f.exists()) { 464 return props; 465 } 466 try { 467 FileInputStream in = new FileInputStream(f); 468 try { 469 props.load(in); 470 } finally { 471 in.close(); 472 } 473 } catch (IOException e) { 474 e.printStackTrace(); 475 throw new RuntimeException("extra property setup failed", e); 476 } 477 return props; 478 } 479 480 /** 481 * Returns an extra test property. Looks for the file "../../test.props" 482 * and reads it in as a Properties file. Assuming the working directory 483 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 484 * If the property isn't found, defaultVal is returned. 485 */ 486 public static String getExtraProperty(String property, String defaultVal) { 487 return getExtraProperties().getProperty(property, defaultVal); 488 } 489 }