--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/namespace/JMXNamespaceTest.java Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,714 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ *
+ * @test JMXNamespaceTest.java
+ * @summary General JMXNamespace test.
+ * @author Daniel Fuchs
+ * @run clean JMXNamespaceTest
+ * Wombat WombatMBean JMXRemoteTargetNamespace
+ * NamespaceController NamespaceControllerMBean
+ * @compile -XDignore.symbol.file=true JMXNamespaceTest.java
+ * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java
+ * NamespaceController.java NamespaceControllerMBean.java
+ * @run main/othervm JMXNamespaceTest
+ */
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+import javax.management.DynamicMBean;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.NotificationEmitter;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+import javax.management.StandardMBean;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespaceMBean;
+import javax.management.namespace.JMXRemoteNamespaceMBean;
+import javax.management.namespace.MBeanServerConnectionWrapper;
+import javax.management.namespace.MBeanServerSupport;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ * @author Sun Microsystems, Inc.
+ */
+public class JMXNamespaceTest {
+
+ /**
+ * A logger for this class.
+ **/
+ private static final Logger LOG =
+ Logger.getLogger(JMXNamespaceTest.class.getName());
+
+ /** Creates a new instance of JMXNamespaceTest */
+ public JMXNamespaceTest() {
+ }
+
+ public static class WombatRepository extends MBeanServerSupport {
+ final Wombat wombat;
+ final StandardMBean mbean;
+ final ObjectName wombatName;
+
+ public WombatRepository(ObjectName wombatName) {
+ try {
+ wombat = new Wombat();
+ mbean = wombat;
+ this.wombatName = wombatName;
+ wombat.preRegister(null,wombatName);
+ } catch (Exception x) {
+ throw new IllegalArgumentException(x);
+ }
+ }
+
+ @Override
+ public DynamicMBean getDynamicMBeanFor(ObjectName name)
+ throws InstanceNotFoundException {
+ if (wombatName.equals(name)) return mbean;
+ else throw new InstanceNotFoundException(String.valueOf(name));
+ }
+
+ @Override
+ protected Set<ObjectName> getNames() {
+ final Set<ObjectName> res = Collections.singleton(wombatName);
+ return res;
+ }
+
+ @Override
+ public NotificationEmitter
+ getNotificationEmitterFor(ObjectName name)
+ throws InstanceNotFoundException {
+ final DynamicMBean mb = getDynamicMBeanFor(name);
+ if (mb instanceof NotificationEmitter)
+ return (NotificationEmitter)mb;
+ return null;
+ }
+ }
+
+ public static class SimpleTest {
+ public final String descr;
+ private final Class<?> testClass;
+ private final Method method;
+ public SimpleTest(String descr) {
+ this.descr = descr;
+ this.testClass = JMXNamespaceTest.class;
+ try {
+ method = testClass.
+ getDeclaredMethod(descr,SimpleTestConf.class,
+ Object[].class);
+ } catch (NoSuchMethodException x) {
+ throw new IllegalArgumentException(descr+": test not found",
+ x);
+ }
+ }
+
+ public void run(SimpleTestConf conf, Object... args)
+ throws Exception {
+ try {
+ method.invoke(null,conf,args);
+ } catch (InvocationTargetException x) {
+ final Throwable cause = x.getCause();
+ if (cause instanceof Exception) throw (Exception)cause;
+ if (cause instanceof Error) throw (Error)cause;
+ throw x;
+ }
+ }
+ }
+
+ private static class SimpleTestConf {
+ public final Wombat wombat;
+ public final StandardMBean mbean;
+ public final String dirname;
+ public final ObjectName handlerName;
+ public final ObjectName wombatNickName;
+ public final ObjectName wombatName;
+ public final JMXNamespace wombatNamespace;
+ public final MBeanServer server;
+ public final WombatMBean proxy;
+ public SimpleTestConf(String[] args) throws Exception {
+ wombat = new Wombat();
+ mbean = wombat;
+ dirname = "wombat";
+ handlerName =
+ new ObjectName(dirname+"//:type=JMXNamespace");
+
+ wombatNickName =
+ new ObjectName("burrow:type=Wombat");
+
+ wombatName =
+ new ObjectName(dirname+"//"+wombatNickName);
+
+ wombatNamespace =
+ new JMXNamespace(
+ new WombatRepository(wombatNickName));
+
+ server = ManagementFactory.getPlatformMBeanServer();
+ System.out.println(handlerName+" registered="+
+ server.isRegistered(handlerName));
+ server.registerMBean(wombatNamespace,handlerName);
+
+ try {
+ proxy = JMX.newMBeanProxy(server,wombatName,
+ WombatMBean.class);
+ } catch (Exception x) {
+ server.unregisterMBean(handlerName);
+ throw x;
+ }
+ }
+
+ public void close() {
+ try {
+ server.unregisterMBean(handlerName);
+ } catch (Exception x) {
+ System.out.println("Failed to close: " + x);
+ x.printStackTrace();
+ }
+ }
+
+ public void test(SimpleTest test,Object... args)
+ throws Exception {
+ try {
+ test.run(this,args);
+ passed++;
+ } catch (Exception x) {
+ failed++;
+ System.err.println(test.descr+" failed: " + x);
+ x.printStackTrace();
+ }
+ }
+
+ public volatile int failed = 0;
+ public volatile int passed = 0;
+ }
+
+ static void checkValue(String name,Object expected, Object returned)
+ throws InvalidAttributeValueException {
+ if (Collections.singletonList(expected).
+ equals(Collections.singletonList(returned))) return;
+
+ throw new InvalidAttributeValueException("Bad value for "+
+ name+": ["+returned+"] - was expecting ["+expected+"]");
+ }
+
+ // ---------------------------------------------------------------
+ // SIMPLE TESTS BEGIN HERE
+ // ---------------------------------------------------------------
+
+ static void getCaptionTest(SimpleTestConf env, Object... args)
+ throws Exception {
+ System.out.println(env.proxy.getCaption());
+ }
+
+ static void setCaptionTest(SimpleTestConf env, Object... args)
+ throws Exception {
+ env.proxy.setCaption((String)args[0]);
+ final String result = env.proxy.getCaption();
+ System.out.println(result);
+ checkValue("Caption",args[0],result);
+ }
+
+ static void queryNamesTest1(SimpleTestConf env, Object... args)
+ throws Exception {
+ final ObjectName pat =
+ new ObjectName(env.handlerName.getDomain()+"*:*");
+ final Set<ObjectName> res =
+ env.server.queryNames(pat,null);
+ System.out.println("queryNamesTest1: "+res);
+ checkValue("names",Collections.singleton(env.wombatName),res);
+ }
+
+ static void queryNamesTest2(SimpleTestConf env, Object... args)
+ throws Exception {
+ final ObjectName pat =
+ new ObjectName("*:"+
+ env.wombatName.getKeyPropertyListString());
+ final Set<ObjectName> res =
+ env.server.queryNames(pat,null);
+ System.out.println("queryNamesTest2: "+res);
+ checkValue("names",Collections.emptySet(),res);
+ }
+
+ static void getDomainsTest(SimpleTestConf env, Object... args)
+ throws Exception {
+ final List<String> domains =
+ Arrays.asList(env.server.getDomains());
+ System.out.println("getDomainsTest: "+domains);
+ if (domains.contains(env.wombatName.getDomain()))
+ throw new InvalidAttributeValueException("domain: "+
+ env.wombatName.getDomain());
+ if (!domains.contains(env.handlerName.getDomain()))
+ throw new InvalidAttributeValueException("domain not found: "+
+ env.handlerName.getDomain());
+ }
+
+ // ---------------------------------------------------------------
+ // SIMPLE TESTS END HERE
+ // ---------------------------------------------------------------
+
+ private static void simpleTest(String[] args) {
+ final SimpleTestConf conf;
+ try {
+ conf = new SimpleTestConf(args);
+ try {
+ conf.test(new SimpleTest("getCaptionTest"));
+ conf.test(new SimpleTest("setCaptionTest"),
+ "I am a new Wombat!");
+ conf.test(new SimpleTest("queryNamesTest1"));
+ conf.test(new SimpleTest("queryNamesTest2"));
+ conf.test(new SimpleTest("getDomainsTest"));
+ } finally {
+ conf.close();
+ }
+ } catch (Exception x) {
+ System.err.println("simpleTest FAILED: " +x);
+ x.printStackTrace();
+ throw new RuntimeException(x);
+ }
+ System.out.println("simpleTest: "+conf.passed+
+ " PASSED, " + conf.failed + " FAILED.");
+ if (conf.failed>0) {
+ System.err.println("simpleTest FAILED ["+conf.failed+"]");
+ throw new RuntimeException("simpleTest FAILED ["+conf.failed+"]");
+ } else {
+ System.err.println("simpleTest PASSED ["+conf.passed+"]");
+ }
+ }
+
+ public static void recursiveTest(String[] args) {
+ final SimpleTestConf conf;
+ try {
+ conf = new SimpleTestConf(args);
+ try {
+ final JMXServiceURL url =
+ new JMXServiceURL("rmi","localHost",0);
+ final Map<String,Object> empty = Collections.emptyMap();
+ final JMXConnectorServer server =
+ JMXConnectorServerFactory.newJMXConnectorServer(url,
+ empty,conf.server);
+ server.start();
+ final JMXServiceURL address = server.getAddress();
+ final JMXConnector client =
+ JMXConnectorFactory.connect(address,
+ empty);
+ final String[] signature = {
+ JMXServiceURL.class.getName(),
+ Map.class.getName(),
+ };
+ final String[] signature2 = {
+ JMXServiceURL.class.getName(),
+ Map.class.getName(),
+ String.class.getName(),
+ };
+ final Object[] params = {
+ address,
+ null,
+ };
+ final MBeanServerConnection c =
+ client.getMBeanServerConnection();
+ final ObjectName dirName1 =
+ new ObjectName("kanga//:type=JMXNamespace");
+ c.createMBean(JMXRemoteTargetNamespace.class.getName(),
+ dirName1, params,signature);
+ c.invoke(dirName1, "connect", null, null);
+ try {
+ final MemoryMXBean memory =
+ JMX.newMXBeanProxy(c,
+ new ObjectName("kanga//"+
+ ManagementFactory.MEMORY_MXBEAN_NAME),
+ MemoryMXBean.class);
+ System.out.println("HeapMemory #1: "+
+ memory.getHeapMemoryUsage().toString());
+ final MemoryMXBean memory2 =
+ JMX.newMXBeanProxy(c,
+ new ObjectName("kanga//kanga//"+
+ ManagementFactory.MEMORY_MXBEAN_NAME),
+ MemoryMXBean.class);
+ System.out.println("HeapMemory #2: "+
+ memory2.getHeapMemoryUsage().toString());
+ final Object[] params2 = {
+ address,
+ null,
+ "kanga//kanga"
+ // "kanga//kanga//roo//kanga", <= cycle
+ };
+ final ObjectName dirName2 =
+ new ObjectName("kanga//roo//:type=JMXNamespace");
+ c.createMBean(JMXRemoteTargetNamespace.class.getName(),
+ dirName2, params2, signature2);
+ System.out.println(dirName2 + " created!");
+ JMX.newMBeanProxy(c,dirName2,
+ JMXRemoteNamespaceMBean.class).connect();
+ try {
+ final ObjectName wombatName1 =
+ new ObjectName("kanga//roo//"+conf.wombatName);
+ final ObjectName wombatName2 =
+ new ObjectName("kanga//roo//"+wombatName1);
+ final WombatMBean wombat1 =
+ JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
+ final WombatMBean wombat2 =
+ JMX.newMBeanProxy(c,wombatName2,WombatMBean.class);
+ final String newCaption="I am still the same old wombat";
+ wombat1.setCaption(newCaption);
+ final String caps = conf.proxy.getCaption();
+ System.out.println("Caption: "+caps);
+ checkValue("Caption",newCaption,caps);
+ final String caps1 = wombat1.getCaption();
+ System.out.println("Caption #1: "+caps1);
+ checkValue("Caption #1",newCaption,caps1);
+ final String caps2 = wombat2.getCaption();
+ System.out.println("Caption #2: "+caps2);
+ checkValue("Caption #2",newCaption,caps2);
+ final ObjectInstance instance =
+ NamespaceController.createInstance(conf.server);
+ final NamespaceControllerMBean controller =
+ JMX.newMBeanProxy(conf.server,instance.getObjectName(),
+ NamespaceControllerMBean.class);
+ final String[] dirs = controller.findNamespaces();
+ System.out.println("directories: " +
+ Arrays.asList(dirs));
+ final int depth = 4;
+ final String[] dirs2 = controller.findNamespaces(null,null,depth);
+ System.out.println("directories[depth="+depth+"]: " +
+ Arrays.asList(dirs2));
+ for (String dir : dirs2) {
+ if (dir.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR))
+ dir = dir.substring(0,dir.length()-
+ JMXNamespaces.NAMESPACE_SEPARATOR.length());
+ if (dir.split(JMXNamespaces.NAMESPACE_SEPARATOR).length
+ > (depth+1)) {
+ throw new RuntimeException(dir+": depth exceeds "+depth);
+ }
+ final ObjectName handlerName =
+ JMXNamespaces.getNamespaceObjectName(dir);
+ final JMXNamespaceMBean handler =
+ JMX.newMBeanProxy(conf.server,handlerName,
+ JMXNamespaceMBean.class);
+ try {
+ System.err.println("Directory "+dir+" domains: "+
+ Arrays.asList(handler.getDomains()));
+ System.err.println("Directory "+dir+" default domain: "+
+ handler.getDefaultDomain());
+ System.err.println("Directory "+dir+" MBean count: "+
+ handler.getMBeanCount());
+ } catch(Exception x) {
+ System.err.println("get info failed for " +
+ dir +", "+handlerName+": "+x);
+ x.getCause().printStackTrace();
+ throw x;
+ }
+ }
+
+ } finally {
+ c.unregisterMBean(dirName2);
+ }
+ } finally {
+ c.unregisterMBean(dirName1);
+ client.close();
+ server.stop();
+ }
+ } finally {
+ conf.close();
+ }
+ System.err.println("recursiveTest PASSED");
+ } catch (Exception x) {
+ System.err.println("recursiveTest FAILED: " +x);
+ x.printStackTrace();
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * Test cycle detection.
+ * mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo
+ * touch kanga/roo/wombat
+ **/
+ public static void probeKangaRooTest(String[] args) {
+ final SimpleTestConf conf;
+ try {
+ conf = new SimpleTestConf(args);
+ try {
+ final JMXServiceURL url =
+ new JMXServiceURL("rmi","localHost",0);
+ final Map<String,Object> empty = Collections.emptyMap();
+ final JMXConnectorServer server =
+ JMXConnectorServerFactory.newJMXConnectorServer(url,
+ empty,conf.server);
+ server.start();
+ final JMXServiceURL address = server.getAddress();
+ final JMXConnector client =
+ JMXConnectorFactory.connect(address,
+ empty);
+ final String[] signature = {
+ JMXServiceURL.class.getName(),
+ Map.class.getName(),
+ };
+
+ final Object[] params = {
+ address,
+ null,
+ };
+ final MBeanServerConnection c =
+ client.getMBeanServerConnection();
+
+ // ln -s . kanga
+ final ObjectName dirName1 =
+ new ObjectName("kanga//:type=JMXNamespace");
+ c.createMBean(JMXRemoteTargetNamespace.class.getName(),
+ dirName1, params,signature);
+ c.invoke(dirName1, "connect", null, null);
+ try {
+ // ln -s kanga//kanga//roo//kanga roo
+ final JMXNamespace local = new JMXNamespace(
+ new MBeanServerConnectionWrapper(null,
+ JMXNamespaceTest.class.getClassLoader()){
+
+ @Override
+ protected MBeanServerConnection getMBeanServerConnection() {
+ return JMXNamespaces.narrowToNamespace(c,
+ "kanga//kanga//roo//kanga"
+ );
+ }
+
+ });
+ final ObjectName dirName2 =
+ new ObjectName("roo//:type=JMXNamespace");
+ conf.server.registerMBean(local,dirName2);
+ System.out.println(dirName2 + " created!");
+ try {
+ // touch kanga/roo/wombat
+ final ObjectName wombatName1 =
+ new ObjectName("kanga//roo//"+conf.wombatName);
+ final WombatMBean wombat1 =
+ JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
+ final String newCaption="I am still the same old wombat";
+ Exception x = null;
+ try {
+ wombat1.setCaption(newCaption);
+ } catch (RuntimeOperationsException r) {
+ x=r.getTargetException();
+ System.out.println("Got expected exception: " + x);
+ // r.printStackTrace();
+ }
+ if (x == null)
+ throw new RuntimeException("cycle not detected!");
+ } finally {
+ c.unregisterMBean(dirName2);
+ }
+ } finally {
+ c.unregisterMBean(dirName1);
+ client.close();
+ server.stop();
+ }
+ } finally {
+ conf.close();
+ }
+ System.err.println("probeKangaRooTest PASSED");
+ } catch (Exception x) {
+ System.err.println("probeKangaRooTest FAILED: " +x);
+ x.printStackTrace();
+ throw new RuntimeException(x);
+ }
+ }
+ /**
+ * Test cycle detection 2.
+ * mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga
+ * touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ;
+ * touch kanga/roo/wombat
+ *
+ **/
+ public static void probeKangaRooCycleTest(String[] args) {
+ final SimpleTestConf conf;
+ try {
+ conf = new SimpleTestConf(args);
+ Exception failed = null;
+ try {
+ final JMXServiceURL url =
+ new JMXServiceURL("rmi","localHost",0);
+ final Map<String,Object> empty = Collections.emptyMap();
+ final JMXConnectorServer server =
+ JMXConnectorServerFactory.newJMXConnectorServer(url,
+ empty,conf.server);
+ server.start();
+ final JMXServiceURL address = server.getAddress();
+ final JMXConnector client =
+ JMXConnectorFactory.connect(address,
+ empty);
+ final String[] signature = {
+ JMXServiceURL.class.getName(),
+ Map.class.getName(),
+ };
+ final String[] signature2 = {
+ JMXServiceURL.class.getName(),
+ Map.class.getName(),
+ String.class.getName()
+ };
+ final Object[] params = {
+ address,
+ Collections.emptyMap(),
+ };
+ final Object[] params2 = {
+ address,
+ null,
+ "kanga",
+ };
+ final MBeanServerConnection c =
+ client.getMBeanServerConnection();
+
+ // ln -s . roo
+ final ObjectName dirName1 =
+ new ObjectName("roo//:type=JMXNamespace");
+ c.createMBean(JMXRemoteTargetNamespace.class.getName(),
+ dirName1, params,signature);
+ c.invoke(dirName1, "connect",null,null);
+ try {
+ final Map<String,Object> emptyMap =
+ Collections.emptyMap();
+ final JMXNamespace local = new JMXNamespace(
+ new MBeanServerConnectionWrapper(
+ JMXNamespaces.narrowToNamespace(c,
+ "roo//roo//"),
+ JMXNamespaceTest.class.getClassLoader())) {
+ };
+ // ln -s roo/roo kanga
+ final ObjectName dirName2 =
+ new ObjectName("kanga//:type=JMXNamespace");
+ conf.server.registerMBean(local,dirName2);
+ System.out.println(dirName2 + " created!");
+ try {
+ // touch kanga/roo/wombat
+ final ObjectName wombatName1 =
+ new ObjectName("kanga//roo//"+conf.wombatName);
+ final WombatMBean wombat1 =
+ JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
+ final String newCaption="I am still the same old wombat";
+ wombat1.setCaption(newCaption);
+ // rm roo
+ c.unregisterMBean(dirName1);
+ // ln -s kanga roo
+ System.err.println("**** Creating " + dirName1 +
+ " ****");
+ c.createMBean(JMXRemoteTargetNamespace.class.getName(),
+ dirName1, params2,signature2);
+ System.err.println("**** Created " + dirName1 +
+ " ****");
+ Exception x = null;
+ try {
+ // touch kanga/roo/wombat
+ wombat1.setCaption(newCaption+" I hope");
+ } catch (RuntimeOperationsException r) {
+ x=(Exception)r.getCause();
+ System.out.println("Got expected exception: " + x);
+ //r.printStackTrace();
+ }
+ if (x == null)
+ throw new RuntimeException("should have failed!");
+ x = null;
+ try {
+ // ls kanga/roo/wombat
+ System.err.println("**** Connecting " + dirName1 +
+ " ****");
+ JMX.newMBeanProxy(c,dirName1,
+ JMXRemoteNamespaceMBean.class).connect();
+ System.err.println("**** Connected " + dirName1 +
+ " ****");
+ } catch (IOException r) {
+ x=r;
+ System.out.println("Got expected exception: " + x);
+ //r.printStackTrace();
+ }
+ System.err.println("**** Expected Exception Not Raised ****");
+ if (x == null) {
+ System.out.println(dirName1+" contains: "+
+ c.queryNames(new ObjectName(
+ dirName1.getDomain()+"*:*"),null));
+ throw new RuntimeException("cycle not detected!");
+ }
+ } catch (Exception t) {
+ if (failed == null) failed = t;
+ } finally {
+ c.unregisterMBean(dirName2);
+ }
+ } finally {
+ try {
+ c.unregisterMBean(dirName1);
+ } catch (Exception t) {
+ if (failed == null) failed = t;
+ System.err.println("Failed to unregister "+dirName1+
+ ": "+t);
+ }
+ try {
+ client.close();
+ } catch (Exception t) {
+ if (failed == null) failed = t;
+ System.err.println("Failed to close client: "+t);
+ }
+ try {
+ server.stop();
+ } catch (Exception t) {
+ if (failed == null) failed = t;
+ System.err.println("Failed to stop server: "+t);
+ }
+ }
+ } finally {
+ try {
+ conf.close();
+ } catch (Exception t) {
+ if (failed == null) failed = t;
+ System.err.println("Failed to stop server: "+t);
+ }
+ }
+ if (failed != null) throw failed;
+ System.err.println("probeKangaRooCycleTest PASSED");
+ } catch (Exception x) {
+ System.err.println("probeKangaRooCycleTest FAILED: " +x);
+ x.printStackTrace();
+ throw new RuntimeException(x);
+ }
+ }
+ public static void main(String[] args) {
+ simpleTest(args);
+ recursiveTest(args);
+ probeKangaRooTest(args);
+ probeKangaRooCycleTest(args);
+ }
+
+}