blob: 6ee23920115de67d89f6818f193b2d1a3d37f570 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23import sun.management.jmxremote.ConnectorBootstrap;
24
25import java.io.File;
26import java.io.FileInputStream;
27import java.io.InputStream;
28import java.io.FilenameFilter;
29import java.io.IOException;
30
31import java.util.Properties;
32import java.util.Iterator;
33import java.util.Set;
34import java.util.Arrays;
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.Map;
38import java.util.Enumeration;
39
40import javax.management.remote.*;
41import javax.management.*;
42
43import sun.management.AgentConfigurationError;
44
45import util.TestLogger;
46
47/**
48 * <p>This class implements unit test for RMI Bootstrap.
49 * When called with no arguments main() looks in the directory indicated
50 * by the "test.src" system property for files called management*ok.properties
51 * or management*ko.properties. The *ok.properties files are assumed to be
52 * valid Java M&M config files for which the bootstrap should succeed.
53 * The *ko.properties files are assumed to be configurations for which the
54 * bootstrap & connection test will fail.</p>
55 *
56 * <p>The rmi port number can be specified with the "rmi.port" system property.
57 * If not, this test will use 12424</p>
58 *
59 * <p>When called with some argument, the main() will interprete its args to
60 * be Java M&M configuration file names. The filenames are expected to end
61 * with ok.properties or ko.properties - and are interpreted as above.</p>
62 *
63 * <p>Note that a limitation of the RMI registry (bug 4267864) prevent
64 * this test from succeeding if more than 1 configuration is used.
65 * As long as 4267864 isn't fix, this test must be called as many times
66 * as needed but with a single argument (no arguments, or several arguments
67 * will fail).</p>
68 *
69 * <p>Debug traces are logged in "sun.management.test"</p>
70 **/
71public class RmiBootstrapTest {
72
73 static TestLogger log =
74 new TestLogger("RmiBootstrapTest");
75
76 /**
77 * When launching several registries, we increment the port number
78 * to avoid falling into "port number already in use" problems.
79 **/
80 static int testPort = 0;
81
82 /**
83 * Default values for RMI configuration properties.
84 **/
85 public static interface DefaultValues {
86 public static final String PORT="0";
87 public static final String CONFIG_FILE_NAME="management.properties";
88 public static final String USE_SSL="true";
89 public static final String USE_AUTHENTICATION="true";
90 public static final String PASSWORD_FILE_NAME="jmxremote.password";
91 public static final String ACCESS_FILE_NAME="jmxremote.access";
92 public static final String KEYSTORE="keystore";
93 public static final String KEYSTORE_PASSWD="password";
94 public static final String TRUSTSTORE="truststore";
95 public static final String TRUSTSTORE_PASSWD="trustword";
96 public static final String SSL_NEED_CLIENT_AUTH="false";
97 }
98
99 /**
100 * Names of RMI configuration properties.
101 **/
102 public static interface PropertyNames {
103 public static final String PORT=
104 "com.sun.management.jmxremote.port";
105 public static final String CONFIG_FILE_NAME=
106 "com.sun.management.config.file";
107 public static final String USE_SSL=
108 "com.sun.management.jmxremote.ssl";
109 public static final String USE_AUTHENTICATION=
110 "com.sun.management.jmxremote.authenticate";
111 public static final String PASSWORD_FILE_NAME=
112 "com.sun.management.jmxremote.password.file";
113 public static final String ACCESS_FILE_NAME=
114 "com.sun.management.jmxremote.access.file";
115 public static final String INSTRUMENT_ALL=
116 "com.sun.management.instrumentall";
117 public static final String CREDENTIALS =
118 "jmx.remote.credentials";
119 public static final String KEYSTORE=
120 "javax.net.ssl.keyStore";
121 public static final String KEYSTORE_PASSWD=
122 "javax.net.ssl.keyStorePassword";
123 public static final String TRUSTSTORE=
124 "javax.net.ssl.trustStore";
125 public static final String TRUSTSTORE_PASSWD=
126 "javax.net.ssl.trustStorePassword";
127 public static final String SSL_ENABLED_CIPHER_SUITES =
128 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
129 public static final String SSL_ENABLED_PROTOCOLS =
130 "com.sun.management.jmxremote.ssl.enabled.protocols";
131 public static final String SSL_NEED_CLIENT_AUTH =
132 "com.sun.management.jmxremote.ssl.need.client.auth";
133 }
134
135 /**
136 * A filter to find all filenames who match <prefix>*<suffix>.
137 * Note that <prefix> and <suffix> can overlap.
138 **/
139 private static class ConfigFilenameFilter implements FilenameFilter {
140 final String suffix;
141 final String prefix;
142 ConfigFilenameFilter(String prefix, String suffix) {
143 this.suffix=suffix;
144 this.prefix=prefix;
145 }
146 public boolean accept(File dir, String name) {
147 return (name.startsWith(prefix) && name.endsWith(suffix));
148 }
149 }
150
151 /**
152 * Get all "management*ok.properties" files in the directory
153 * indicated by the "test.src" management property.
154 **/
155 private static File[] findConfigurationFilesOk() {
156 final String testSrc = System.getProperty("test.src");
157 final File dir = new File(testSrc);
158 final FilenameFilter filter =
159 new ConfigFilenameFilter("management_test","ok.properties");
160 return dir.listFiles(filter);
161 }
162
163 /**
164 * Get all "management*ko.properties" files in the directory
165 * indicated by the "test.src" management property.
166 **/
167 private static File[] findConfigurationFilesKo() {
168 final String testSrc = System.getProperty("test.src");
169 final File dir = new File(testSrc);
170 final FilenameFilter filter =
171 new ConfigFilenameFilter("management_test","ko.properties");
172 return dir.listFiles(filter);
173 }
174
175 /**
176 * List all MBeans and their attributes. Used to test communication
177 * with the Java M&M MBean Server.
178 * @return the number of queried MBeans.
179 */
180 public static int listMBeans(MBeanServerConnection server)
181 throws IOException {
182 return listMBeans(server,null,null);
183 }
184
185 /**
186 * List all matching MBeans and their attributes.
187 * Used to test communication with the Java M&M MBean Server.
188 * @return the number of matching MBeans.
189 */
190 public static int listMBeans(MBeanServerConnection server,
191 ObjectName pattern, QueryExp query)
192 throws IOException {
193
194 final Set names = server.queryNames(pattern,query);
195 for (final Iterator i=names.iterator(); i.hasNext(); ) {
196 ObjectName name = (ObjectName)i.next();
197 log.trace("listMBeans","Got MBean: "+name);
198 try {
199 MBeanInfo info =
200 server.getMBeanInfo((ObjectName)name);
201 MBeanAttributeInfo[] attrs = info.getAttributes();
202 if (attrs == null) continue;
203 for (int j=0; j<attrs.length; j++) {
204 if (attrs[j].isReadable()) {
205 try {
206 Object o =
207 server.getAttribute(name,attrs[j].getName());
208 if (log.isDebugOn())
209 log.debug("listMBeans","\t\t" +
210 attrs[j].getName() +
211 " = "+o);
212 } catch (Exception x) {
213 log.trace("listMBeans","JmxClient failed to get " +
214 attrs[j].getName() + ": " + x);
215 final IOException io =
216 new IOException("JmxClient failed to get " +
217 attrs[j].getName());
218 io.initCause(x);
219 throw io;
220 }
221 }
222 }
223 } catch (Exception x) {
224 log.trace("listMBeans",
225 "JmxClient failed to get MBeanInfo: " + x);
226 final IOException io =
227 new IOException("JmxClient failed to get MBeanInfo: "+x);
228 io.initCause(x);
229 throw io;
230 }
231 }
232 return names.size();
233 }
234
235 /**
236 * Compute the full path name for a default file.
237 * @param basename basename (with extension) of the default file.
238 * @return ${JRE}/lib/management/${basename}
239 **/
240 private static String getDefaultFileName(String basename) {
241 final String fileSeparator = File.separator;
242 final StringBuffer defaultFileName =
243 new StringBuffer(System.getProperty("java.home")).
244 append(fileSeparator).append("lib").append(fileSeparator).
245 append("management").append(fileSeparator).
246 append(basename);
247 return defaultFileName.toString();
248 }
249
250 /**
251 * Compute the full path name for a default file.
252 * @param basename basename (with extension) of the default file.
253 * @return ${JRE}/lib/management/${basename}
254 **/
255 private static String getDefaultStoreName(String basename) {
256 final String fileSeparator = File.separator;
257 final StringBuffer defaultFileName =
258 new StringBuffer(System.getProperty("test.src")).
259 append(fileSeparator).append("ssl").append(fileSeparator).
260 append(basename);
261 return defaultFileName.toString();
262 }
263
264
265 /**
266 * Parses the password file to read the credentials.
267 * Returns an ArrayList of arrays of 2 string:
268 * {<subject>, <password>}.
269 * If the password file does not exists, return an empty list.
270 * (File not found = empty file).
271 **/
272 private ArrayList readCredentials(String passwordFileName)
273 throws IOException {
274 final Properties pws = new Properties();
275 final ArrayList result = new ArrayList();
276 final File f = new File(passwordFileName);
277 if (!f.exists()) return result;
278 FileInputStream fin = new FileInputStream(passwordFileName);
279 try {pws.load(fin);}finally{fin.close();}
280 for (Enumeration en=pws.propertyNames();en.hasMoreElements();) {
281 final String[] cred = new String[2];
282 cred[0]=(String)en.nextElement();
283 cred[1]=pws.getProperty(cred[0]);
284 result.add(cred);
285 }
286 return result;
287 }
288
289
290 /**
291 * Connect with the given url, using all given credentials in turn.
292 * A null entry in the useCredentials arrays indicate a connection
293 * where no credentials are used.
294 * @param url JMXServiceURL of the server.
295 * @param useCredentials An array of credentials (a credential
296 * is a two String array, so this is an array of arrays
297 * of strings:
298 * useCredentials[i][0]=subject
299 * useCredentials[i][1]=password
300 * if useCredentials[i] == null means no credentials.
301 * @param expectConnectOk true if connection is expected to succeed
302 * Note: if expectConnectOk=false and the test fails to connect
303 * the number of failure is not incremented. Conversely,
304 * if expectConnectOk=false and the test does not fail to
305 * connect the number of failure is incremented.
306 * @param expectReadOk true if communication (listMBeans) is expected
307 * to succeed.
308 * Note: if expectReadOk=false and the test fails to read MBeans
309 * the number of failure is not incremented. Conversely,
310 * if expectReadOk=false and the test does not fail to
311 * read MBeans the number of failure is incremented.
312 * @return number of failure.
313 **/
314 public int connectAndRead(JMXServiceURL url,
315 Object[] useCredentials,
316 boolean expectConnectOk,
317 boolean expectReadOk)
318 throws IOException {
319
320 int errorCount = 0;
321
322 for (int i=0 ; i<useCredentials.length ; i++) {
323 final Map m = new HashMap();
324 final String[] credentials = (String[])useCredentials[i];
325 final String crinfo;
326 if (credentials != null) {
327 crinfo = "{"+credentials[0] + ", " + credentials[1] + "}";
328 m.put(PropertyNames.CREDENTIALS,credentials);
329 } else {
330 crinfo="no credentials";
331 }
332 log.trace("testCommunication","using credentials: " + crinfo);
333
334 final JMXConnector c;
335 try {
336 c = JMXConnectorFactory.connect(url,m);
337 } catch (IOException x ) {
338 if (expectConnectOk) {
339 final String err = "Connection failed for " + crinfo +
340 ": " + x;
341 System.out.println(err);
342 log.trace("testCommunication",err);
343 log.debug("testCommunication",x);
344 errorCount++;
345 continue;
346 } else {
347 System.out.println("Connection failed as expected for " +
348 crinfo + ": " + x);
349 continue;
350 }
351 } catch (RuntimeException x ) {
352 if (expectConnectOk) {
353 final String err = "Connection failed for " + crinfo +
354 ": " + x;
355 System.out.println(err);
356 log.trace("testCommunication",err);
357 log.debug("testCommunication",x);
358 errorCount++;
359 continue;
360 } else {
361 System.out.println("Connection failed as expected for " +
362 crinfo + ": " + x);
363 continue;
364 }
365 }
366 try {
367 MBeanServerConnection conn =
368 c.getMBeanServerConnection();
369 if (log.isDebugOn()) {
370 log.debug("testCommunication","Connection is:" + conn);
371 log.debug("testCommunication","Server domain is: " +
372 conn.getDefaultDomain());
373 }
374 final ObjectName pattern =
375 new ObjectName("java.lang:type=Memory,*");
376 final int count = listMBeans(conn,pattern,null);
377 if (count == 0)
378 throw new Exception("Expected at least one matching "+
379 "MBean for "+pattern);
380 if (expectReadOk) {
381 System.out.println("Communication succeeded " +
382 "as expected for "+
383 crinfo + ": found " + count
384 + ((count<2)?"MBean":"MBeans"));
385 } else {
386 final String err = "Expected failure didn't occur for " +
387 crinfo;
388 System.out.println(err);
389 errorCount++;
390 }
391 } catch (IOException x ) {
392 if (expectReadOk) {
393 final String err = "Communication failed with " + crinfo +
394 ": " + x;
395 System.out.println(err);
396 log.trace("testCommunication",err);
397 log.debug("testCommunication",x);
398 errorCount++;
399 continue;
400 } else {
401 System.out.println("Communication failed as expected for "+
402 crinfo + ": " + x);
403 continue;
404 }
405 } catch (RuntimeException x ) {
406 if (expectReadOk) {
407 final String err = "Communication failed with " + crinfo +
408 ": " + x;
409 System.out.println(err);
410 log.trace("testCommunication",err);
411 log.debug("testCommunication",x);
412 errorCount++;
413 continue;
414 } else {
415 System.out.println("Communication failed as expected for "+
416 crinfo + ": " + x);
417 }
418 } catch (Exception x) {
419 final String err = "Failed to read MBeans with " + crinfo +
420 ": " + x;
421 System.out.println(err);
422 log.trace("testCommunication",err);
423 log.debug("testCommunication",x);
424 errorCount++;
425 continue;
426 } finally {
427 c.close();
428 }
429 }
430 return errorCount;
431 }
432
433
434 private void setSslProperties() {
435 final String defaultKeyStore =
436 getDefaultStoreName(DefaultValues.KEYSTORE);
437 final String defaultTrustStore =
438 getDefaultStoreName(DefaultValues.TRUSTSTORE);
439
440 final String keyStore =
441 System.getProperty(PropertyNames.KEYSTORE, defaultKeyStore);
442 System.setProperty(PropertyNames.KEYSTORE,keyStore);
443 log.trace("setSslProperties",PropertyNames.KEYSTORE+"="+keyStore);
444
445 final String password =
446 System.getProperty(PropertyNames.KEYSTORE_PASSWD,
447 DefaultValues.KEYSTORE_PASSWD);
448 System.setProperty(PropertyNames.KEYSTORE_PASSWD,password);
449 log.trace("setSslProperties",
450 PropertyNames.KEYSTORE_PASSWD+"="+password);
451
452 final String trustStore =
453 System.getProperty(PropertyNames.TRUSTSTORE,
454 defaultTrustStore);
455 System.setProperty(PropertyNames.TRUSTSTORE,trustStore);
456 log.trace("setSslProperties",
457 PropertyNames.TRUSTSTORE+"="+trustStore);
458
459 final String trustword =
460 System.getProperty(PropertyNames.TRUSTSTORE_PASSWD,
461 DefaultValues.TRUSTSTORE_PASSWD);
462 System.setProperty(PropertyNames.TRUSTSTORE_PASSWD,trustword);
463 log.trace("setSslProperties",
464 PropertyNames.TRUSTSTORE_PASSWD+"="+trustword);
465 }
466
467 private void checkSslConfiguration() {
468 try {
469 final String defaultConf =
470 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME);
471 final String confname =
472 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf);
473
474 final Properties props = new Properties();
475 final File conf = new File(confname);
476 if (conf.exists()) {
477 FileInputStream fin = new FileInputStream(conf);
478 try {props.load(fin);} finally {fin.close();}
479 }
480
481 // Do we use SSL?
482 final String useSslStr =
483 props.getProperty(PropertyNames.USE_SSL,
484 DefaultValues.USE_SSL);
485 final boolean useSsl =
486 Boolean.valueOf(useSslStr).booleanValue();
487
488 log.debug("checkSslConfiguration",
489 PropertyNames.USE_SSL+"="+useSsl+
490 ": setting SSL");
491 // Do we use SSL client authentication?
492 final String useSslClientAuthStr =
493 props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
494 DefaultValues.SSL_NEED_CLIENT_AUTH);
495 final boolean useSslClientAuth =
496 Boolean.valueOf(useSslClientAuthStr).booleanValue();
497
498 log.debug("checkSslConfiguration",
499 PropertyNames.SSL_NEED_CLIENT_AUTH+"="+useSslClientAuth);
500
501 // Do we use customized SSL cipher suites?
502 final String sslCipherSuites =
503 props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES);
504
505 log.debug("checkSslConfiguration",
506 PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
507 sslCipherSuites);
508
509 // Do we use customized SSL protocols?
510 final String sslProtocols =
511 props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS);
512
513 log.debug("checkSslConfiguration",
514 PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
515 sslProtocols);
516
517 if (useSsl) setSslProperties();
518 } catch (Exception x) {
519 System.out.println("Failed to setup SSL configuration: " + x);
520 log.debug("checkSslConfiguration",x);
521 }
522 }
523
524 /**
525 * Tests the server bootstraped at the given URL.
526 * Uses the system properties to determine which config file is used.
527 * Loads the config file to determine which password file is used.
528 * Loads the password file to find out wich credentials to use.
529 * Also checks that unregistered user/passwords are not allowed to
530 * connect when a password file is used.
531 *
532 * This method calls connectAndRead().
533 **/
534 public void testCommunication(JMXServiceURL url)
535 throws IOException {
536
537 final String defaultConf =
538 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME);
539 final String confname =
540 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf);
541
542 final Properties props = new Properties();
543 final File conf = new File(confname);
544 if (conf.exists()) {
545 FileInputStream fin = new FileInputStream(conf);
546 try {props.load(fin);} finally {fin.close();}
547 }
548
549 // Do we use authentication?
550 final String useAuthenticationStr =
551 props.getProperty(PropertyNames.USE_AUTHENTICATION,
552 DefaultValues.USE_AUTHENTICATION);
553 final boolean useAuthentication =
554 Boolean.valueOf(useAuthenticationStr).booleanValue();
555
556 // Get Password File
557 final String defaultPasswordFileName = Utils.convertPath(
558 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
559 final String passwordFileName = Utils.convertPath(
560 props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
561 defaultPasswordFileName));
562
563 // Get Access File
564 final String defaultAccessFileName = Utils.convertPath(
565 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
566 final String accessFileName = Utils.convertPath(
567 props.getProperty(PropertyNames.ACCESS_FILE_NAME,
568 defaultAccessFileName));
569
570 if (useAuthentication) {
571 System.out.println("PasswordFileName: " + passwordFileName);
572 System.out.println("accessFileName: " + accessFileName);
573 }
574
575 final Object[] allCredentials;
576 final Object[] noCredentials = { null };
577 if (useAuthentication) {
578 final ArrayList l = readCredentials(passwordFileName);
579 if (l.size() == 0) allCredentials = null;
580 else allCredentials = l.toArray();
581 } else allCredentials = noCredentials;
582
583 int errorCount = 0;
584 if (allCredentials!=null) {
585 // Tests that the registered user/passwords are allowed to
586 // connect & read
587 //
588 errorCount += connectAndRead(url,allCredentials,true,true);
589 } else {
590 // Tests that no one is allowed
591 // connect & read
592 //
593 final String[][] someCredentials = {
594 null,
595 { "modify", "R&D" },
596 { "measure", "QED" }
597 };
598 errorCount += connectAndRead(url,someCredentials,false,false);
599 }
600
601 if (useAuthentication && allCredentials != noCredentials) {
602 // Tests that the registered user/passwords are not allowed to
603 // connect & read
604 //
605 final String[][] badCredentials = {
606 { "bad.user", "R&D" },
607 { "measure", "bad.password" }
608 };
609 errorCount += connectAndRead(url,badCredentials,false,false);
610 }
611 if (errorCount > 0) {
612 final String err = "Test " + confname + " failed with " +
613 errorCount + " error(s)";
614 log.debug("testCommunication",err);
615 throw new RuntimeException(err);
616 }
617 }
618
619
620 /**
621 * Test the configuration indicated by `file'.
622 * Sets the appropriate System properties for config file and
623 * port and then calls ConnectorBootstrap.initialize().
624 * eventually cleans up by calling ConnectorBootstrap.terminate().
625 * @return null if the test succeeds, an error message otherwise.
626 **/
627 private String testConfiguration(File file,int port) {
628
629 final String path;
630 try {
631 path=(file==null)?null:file.getCanonicalPath();
632 } catch(IOException x) {
633 final String err = "Failed to test configuration " + file +
634 ": " + x;
635 log.trace("testConfiguration",err);
636 log.debug("testConfiguration",x);
637 return err;
638 }
639 final String config = (path==null)?"Default config file":path;
640
641 System.out.println("***");
642 System.out.println("*** Testing configuration (port=" + port + "): "
643 + path);
644 System.out.println("***");
645
646 System.setProperty("com.sun.management.jmxremote.port",
647 Integer.toString(port));
648 if (path != null)
649 System.setProperty("com.sun.management.config.file", path);
650 else
651 System.getProperties().remove("com.sun.management.config.file");
652
653 log.trace("testConfiguration","com.sun.management.jmxremote.port="+port);
654 if (path != null && log.isDebugOn())
655 log.trace("testConfiguration",
656 "com.sun.management.config.file="+path);
657
658 checkSslConfiguration();
659
660 final JMXConnectorServer cs;
661 try {
662 cs = ConnectorBootstrap.initialize();
663 } catch (AgentConfigurationError x) {
664 final String err = "Failed to initialize connector:" +
665 "\n\tcom.sun.management.jmxremote.port=" + port +
666 ((path!=null)?"\n\tcom.sun.management.config.file="+path:
667 "\n\t"+config) +
668 "\n\tError is: " + x;
669 log.trace("testConfiguration",err);
670 log.debug("testConfiguration",x);
671 return err;
672 } catch (Exception x) {
673 log.debug("testConfiguration",x);
674 return x.toString();
675 }
676
677 try {
678 JMXServiceURL url =
679 new JMXServiceURL("rmi",null,0,"/jndi/rmi://localhost:"+
680 port+"/jmxrmi");
681
682 try {
683 testCommunication(url);
684 } catch (Exception x) {
685 final String err = "Failed to connect to agent {url="+url+
686 "}: " + x;
687 log.trace("testConfiguration",err);
688 log.debug("testConfiguration",x);
689 return err;
690 }
691 } catch (Exception x) {
692 final String err = "Failed to test configuration "+config+
693 ": "+x;
694 log.trace("testConfiguration",err);
695 log.debug("testConfiguration",x);
696 return err;
697 } finally {
698 try {
699 cs.stop();
700 } catch (Exception x) {
701 final String err = "Failed to terminate: "+x;
702 log.trace("testConfiguration",err);
703 log.debug("testConfiguration",x);
704 }
705 }
706 System.out.println("Configuration " + config + " successfully tested");
707 return null;
708 }
709
710 /**
711 * Test a configuration file which should make the bootstrap fail.
712 * The test is assumed to have succeeded if the bootstrap fails.
713 * @return null if the test succeeds, an error message otherwise.
714 **/
715 private String testConfigurationKo(File conf,int port) {
716 final String errStr = testConfiguration(conf,port+testPort++);
717 if (errStr == null) {
718 return "Configuration " +
719 conf + " should have failed!";
720 }
721 System.out.println("Configuration " +
722 conf + " failed as expected");
723 log.debug("runko","Error was: " + errStr);
724 return null;
725 }
726
727 /**
728 * Test a configuration file. Determines whether the bootstrap
729 * should succeed or fail depending on the file name:
730 * *ok.properties: bootstrap should succeed.
731 * *ko.properties: bootstrap or connection should fail.
732 * @return null if the test succeeds, an error message otherwise.
733 **/
734 private String testConfigurationFile(String fileName) {
735 File file = new File(fileName);
736 final String portStr = System.getProperty("rmi.port","12424");
737 final int port = Integer.parseInt(portStr);
738
739 if (fileName.endsWith("ok.properties")) {
740 return testConfiguration(file,port+testPort++);
741 }
742 if (fileName.endsWith("ko.properties")) {
743 return testConfigurationKo(file,port+testPort++);
744 }
745 return fileName +
746 ": test file suffix must be one of [ko|ok].properties";
747 }
748
749 /**
750 * Find all *ko.property files and test them.
751 * (see findConfigurationFilesKo() and testConfigurationKo())
752 * @throws RuntimeException if the test fails.
753 **/
754 public void runko() {
755 final String portStr = System.getProperty("rmi.port","12424");
756 final int port = Integer.parseInt(portStr);
757 final File[] conf = findConfigurationFilesKo();
758 if ((conf == null)||(conf.length == 0))
759 throw new RuntimeException("No configuration found");
760
761 String errStr;
762 for (int i=0;i<conf.length;i++) {
763 errStr = testConfigurationKo(conf[i],port+testPort++);
764 if (errStr != null) {
765 throw new RuntimeException(errStr);
766 }
767 }
768
769 }
770
771 /**
772 * Find all *ok.property files and test them.
773 * (see findConfigurationFilesOk() and testConfiguration())
774 * @throws RuntimeException if the test fails.
775 **/
776 public void runok() {
777 final String portStr = System.getProperty("rmi.port","12424");
778 final int port = Integer.parseInt(portStr);
779 final File[] conf = findConfigurationFilesOk();
780 if ((conf == null)||(conf.length == 0))
781 throw new RuntimeException("No configuration found");
782
783 String errStr;
784 for (int i=0;i<conf.length;i++) {
785 errStr = testConfiguration(conf[i],port+testPort++);
786 if (errStr != null) {
787 throw new RuntimeException(errStr);
788 }
789 }
790
791 // FIXME: No jmxremote.password is not installed in JRE by default.
792 // - disable the following test case.
793 //
794 // Test default config
795 //
796 // errStr = testConfiguration(null,port+testPort++);
797 // if (errStr != null) {
798 // throw new RuntimeException(errStr);
799 // }
800 }
801
802 /**
803 * Finds all configuration files (*ok.properties and *ko.properties)
804 * and tests them.
805 * (see runko() and runok()).
806 * @throws RuntimeException if the test fails.
807 **/
808 public void run() {
809 runok();
810 runko();
811 }
812
813 /**
814 * Tests the specified configuration files.
815 * If args[] is not empty, each element in args[] is expected to be
816 * a filename ending either by ok.properties or ko.properties.
817 * Otherwise, the configuration files will be automatically determined
818 * by looking at all *.properties files located in the directory
819 * indicated by the System property "test.src".
820 * @throws RuntimeException if the test fails.
821 **/
822 public void run(String args[]) {
823 if (args.length == 0) {
824 run() ; return;
825 }
826 for (int i=0; i<args.length; i++) {
827 final String errStr =testConfigurationFile(args[i]);
828 if (errStr != null) {
829 throw new RuntimeException(errStr);
830 }
831 }
832 }
833
834 /**
835 * Calls run(args[]).
836 * exit(1) if the test fails.
837 **/
838 public static void main(String args[]) {
839 RmiBootstrapTest manager = new RmiBootstrapTest();
840 try {
841 manager.run(args);
842 } catch (RuntimeException r) {
843 System.out.println("Test Failed: "+ r.getMessage());
844 System.exit(1);
845 } catch (Throwable t) {
846 System.out.println("Test Failed: "+ t);
847 t.printStackTrace();
848 System.exit(2);
849 }
850 System.out.println("**** Test RmiBootstrap Passed ****");
851 }
852
853}