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