/** Runs tests using Counter client applications. */ private void exerciseCounters() throws HubTestException, IOException, InterruptedException { Counter c1 = new Counter(); Counter c2 = new Counter(); PlasticConnection conn1 = PlasticUtils.registerRMI(c1); URI id1 = conn1.getId(); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG) != null); assertEquals( removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)), Collections.singletonList(id1)); assertEquals(1, removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)).size()); Object soleId = removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)).get(0); assertEquals(id1, soleId); assertEquals( intMap(new URI[] {id1}, new int[] {0}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(PLUS, 0)))); PlasticConnection conn2 = PlasticUtils.registerXMLRPC(c2); URI id2 = conn2.getId(); assertEquals( new HashSet(Arrays.asList(new URI[] {id1, id2})), new HashSet(removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)))); assertEquals( intMap(new URI[] {id1, id2}, new int[] {10, 10}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(PLUS, 10)))); assertEquals( intMap(new URI[] {id1, id2}, new int[] {5, 5}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(MINUS, 5)))); assertEquals(5, c1.sum_); assertEquals(5, c2.sum_); assertEquals( intMap(new URI[] {id1}, new int[] {95}), hub_.requestToSubset(id_, CALC_MSG, calcArgs(PLUS, 90), Arrays.asList(new URI[] {id1}))); assertEquals(95, c1.sum_); assertEquals(5, c2.sum_); assertEquals( intMap(new URI[] {id2}, new int[] {85}), hub_.requestToSubset(id_, CALC_MSG, calcArgs(PLUS, 80), Arrays.asList(new URI[] {id2}))); assertEquals(95, c1.sum_); assertEquals(85, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; int n2 = c2.nreq_; PlasticUtils.singleRequestAsynch("poke", CALC_MSG, calcArgs(MINUS, 5)); while (c1.nreq_ == n1 || c2.nreq_ == n2) { lock_.wait(); } } assertEquals(90, c1.sum_); assertEquals(80, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; hub_.requestToSubsetAsynch( id_, CALC_MSG, calcArgs(MINUS, 10), Arrays.asList(new URI[] {id1})); while (c1.nreq_ == n1) { lock_.wait(); } } assertEquals(80, c1.sum_); assertEquals(80, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; int n2 = c2.nreq_; hub_.requestAsynch(id_, CALC_MSG, calcArgs(PLUS, 21)); while (c1.nreq_ == n1 || c2.nreq_ == n2) { lock_.wait(); } } assertEquals(101, c1.sum_); assertEquals(101, c2.sum_); assertEquals( objMap(new URI[] {id1}, new String[] {"counter"}), hub_.requestToSubset( id_, PlasticUtils.createURI("ivo://votech.org/info/getName"), new ArrayList(), Arrays.asList(new URI[] {id1}))); assertTrue(hub_.getRegisteredIds().contains(id1)); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG).contains(id1)); assertTrue(!hub_.getMessageRegisteredIds(DUMMY_MSG).contains(id1)); conn1.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id1)); assertTrue(!hub_.getMessageRegisteredIds(CALC_MSG).contains(id1)); assertTrue(hub_.getRegisteredIds().contains(id2)); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG).contains(id2)); conn2.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id2)); assertTrue(!hub_.getMessageRegisteredIds(CALC_MSG).contains(id2)); c1.dispose(); c2.dispose(); }
/** * Runs tests on an existing PlasticHubListener object. The easiest way to use this class is to call * one of the static methods {@link #main}, {@link #testHub()} or {@link * #testHub(org.votech.plastic.PlasticHubListener)}. * * @author Mark Taylor * @since 4 Aug 2006 */ public class HubTester { private final PlasticHubListener hub_; private final URI id_; private List monitors_; private final Object lock_ = new Object(); private final boolean abuse_ = false; private static final String CLIENT_NAME = "test-driver"; private static final URI CALC_MSG = PlasticUtils.createURI("ivo://plastic.starlink.ac.uk/msg/calc"); private static final URI DUMMY_MSG = PlasticUtils.createURI("ivo://plastic.starlink.ac.uk/msg/not-a-message"); private static final String PLUS = "plus"; private static final String MINUS = "minus"; /** Plastic rendezvous file. */ private static final File CONFIG_FILE = new File(System.getProperty("user.home"), PlasticUtils.PLASTIC_FILE); /** * Constructor. * * @param hub hub to test */ public HubTester(PlasticHubListener hub) throws HubTestException { hub_ = hub; id_ = hub.registerNoCallBack(CLIENT_NAME); assertTrue(id_ != null); monitors_ = getMonitors(); } /** * Returns the registered client ID for this tester. * * @return client ID */ public URI getId() { return id_; } /** * Returns hub object with which this tester is registered. * * @return hub */ public PlasticHubListener getHub() { return hub_; } /** Disposes of this tester, clearing up as appropriate. */ public void dispose() throws HubTestException { hub_.unregister(id_); } /** Runs most of the actual tests. */ public void exerciseHub() throws HubTestException { if (hub_ == null || id_ == null) { throw new IllegalStateException("Not initialised"); } assertTrue(CONFIG_FILE.exists()); try { exerciseCounters(); exerciseMonitors(); } catch (IOException e) { throw new HubTestException("Hub failed", e); } catch (InterruptedException e) { throw new HubTestException("Hub failed", e); } } /** Runs tests using Counter client applications. */ private void exerciseCounters() throws HubTestException, IOException, InterruptedException { Counter c1 = new Counter(); Counter c2 = new Counter(); PlasticConnection conn1 = PlasticUtils.registerRMI(c1); URI id1 = conn1.getId(); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG) != null); assertEquals( removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)), Collections.singletonList(id1)); assertEquals(1, removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)).size()); Object soleId = removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)).get(0); assertEquals(id1, soleId); assertEquals( intMap(new URI[] {id1}, new int[] {0}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(PLUS, 0)))); PlasticConnection conn2 = PlasticUtils.registerXMLRPC(c2); URI id2 = conn2.getId(); assertEquals( new HashSet(Arrays.asList(new URI[] {id1, id2})), new HashSet(removeMonitorsList(hub_.getMessageRegisteredIds(CALC_MSG)))); assertEquals( intMap(new URI[] {id1, id2}, new int[] {10, 10}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(PLUS, 10)))); assertEquals( intMap(new URI[] {id1, id2}, new int[] {5, 5}), removeMonitorsMap(hub_.request(id_, CALC_MSG, calcArgs(MINUS, 5)))); assertEquals(5, c1.sum_); assertEquals(5, c2.sum_); assertEquals( intMap(new URI[] {id1}, new int[] {95}), hub_.requestToSubset(id_, CALC_MSG, calcArgs(PLUS, 90), Arrays.asList(new URI[] {id1}))); assertEquals(95, c1.sum_); assertEquals(5, c2.sum_); assertEquals( intMap(new URI[] {id2}, new int[] {85}), hub_.requestToSubset(id_, CALC_MSG, calcArgs(PLUS, 80), Arrays.asList(new URI[] {id2}))); assertEquals(95, c1.sum_); assertEquals(85, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; int n2 = c2.nreq_; PlasticUtils.singleRequestAsynch("poke", CALC_MSG, calcArgs(MINUS, 5)); while (c1.nreq_ == n1 || c2.nreq_ == n2) { lock_.wait(); } } assertEquals(90, c1.sum_); assertEquals(80, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; hub_.requestToSubsetAsynch( id_, CALC_MSG, calcArgs(MINUS, 10), Arrays.asList(new URI[] {id1})); while (c1.nreq_ == n1) { lock_.wait(); } } assertEquals(80, c1.sum_); assertEquals(80, c2.sum_); synchronized (lock_) { int n1 = c1.nreq_; int n2 = c2.nreq_; hub_.requestAsynch(id_, CALC_MSG, calcArgs(PLUS, 21)); while (c1.nreq_ == n1 || c2.nreq_ == n2) { lock_.wait(); } } assertEquals(101, c1.sum_); assertEquals(101, c2.sum_); assertEquals( objMap(new URI[] {id1}, new String[] {"counter"}), hub_.requestToSubset( id_, PlasticUtils.createURI("ivo://votech.org/info/getName"), new ArrayList(), Arrays.asList(new URI[] {id1}))); assertTrue(hub_.getRegisteredIds().contains(id1)); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG).contains(id1)); assertTrue(!hub_.getMessageRegisteredIds(DUMMY_MSG).contains(id1)); conn1.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id1)); assertTrue(!hub_.getMessageRegisteredIds(CALC_MSG).contains(id1)); assertTrue(hub_.getRegisteredIds().contains(id2)); assertTrue(hub_.getMessageRegisteredIds(CALC_MSG).contains(id2)); conn2.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id2)); assertTrue(!hub_.getMessageRegisteredIds(CALC_MSG).contains(id2)); c1.dispose(); c2.dispose(); } private void exerciseMonitors() throws IOException, HubTestException, InterruptedException { PlasticMonitor mon1 = new PlasticMonitor("mon1", true, null, null); PlasticMonitor mon2 = new PlasticMonitor("mon2", false, null, null); ApplicationItem[] regApps = PlasticUtils.getRegisteredApplications(hub_); ApplicationListModel appList1 = new ApplicationListModel(regApps); ApplicationListModel appList2 = new ApplicationListModel(regApps); mon1.setListModel(appList1); mon2.setListModel(appList2); mon1.setHub(hub_); mon2.setHub(hub_); PlasticConnection conn1 = PlasticUtils.registerRMI(mon1); URI id1 = conn1.getId(); assertTrue(hub_.getRegisteredIds().contains(id1)); PlasticConnection conn2 = PlasticUtils.registerXMLRPC(mon2); URI id2 = conn2.getId(); assertTrue(hub_.getRegisteredIds().contains(id2)); Thread.sleep(2000); assertTrue(hub_.getRegisteredIds().contains(id1)); assertTrue(hub_.getRegisteredIds().contains(id2)); conn1.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id1)); conn2.unregister(); assertTrue(!hub_.getRegisteredIds().contains(id2)); } /** * Returns a list of applications which are listening to all messages. This may be non-empty if * the hub already exists with some monitoring listeners registered. This may be needed to * elimintate some returned messages from the hub later. This behaviour should only be encountered * in hubs implementing PLASTIC versions 0.4 and below. * * @return list of application IDs (URIs) which claim to respond to all messages */ private final List getMonitors() throws HubTestException { /* Get a list of applications which are listening to all messages. * This may be non-empty if the hub already exists with some * monitoring listeners registered. We will need this to elimintate * some returned messages from the hub later. This behaviour * should only be encountered in hubs implementing PLASTIC * versions 0.4 and below. */ List monitors = hub_.getMessageRegisteredIds(DUMMY_MSG); assertTrue(monitors != null); float hubVers = getHubVersion(); if (hubVers > 0.49) { assertTrue(monitors.isEmpty()); } return monitors; } /** * Modifies a list so that any monitor-type entries are removed. * * @param list input list of URIs * @return <code>list</code> with any elements of <code>monitors_</code> removed */ private List removeMonitorsList(List list) { if (list == null) { return null; } if (!abuse_) { list = new ArrayList(list); } list.removeAll(monitors_); return list; } /** * Modifies a map so that any monitor-type entries are removed. * * @param map input URI->Object map * @return <code>map</code> with any elements whose keys are elements if <code>monitors_</code> * removed */ private Map removeMonitorsMap(Map map) { if (map == null) { return null; } if (!abuse_) { map = new HashMap(map); } for (Iterator it = monitors_.iterator(); it.hasNext(); ) { map.remove((URI) it.next()); } return map; } /** * Returns the version of the running hub. * * @return version number as a floating point number. */ private final float getHubVersion() throws HubTestException { URI hubId = hub_.getHubId(); Map vMap = hub_.requestToSubset( id_, MessageId.INFO_GETVERSION, new ArrayList(), Collections.singletonList(hubId)); String shubVers = (String) vMap.get(hubId); assertTrue(shubVers != null); try { return Float.parseFloat(shubVers); } catch (NumberFormatException e) { throw new HubTestException( "Version string \"" + shubVers + "\" doesn't have numeric form", e); } } /** * Tests an assertion. * * @param test asserted condition * @throws HubTestException if <code>test</code> is false */ private void assertTrue(boolean test) throws HubTestException { if (!test) { throw new HubTestException("Hub test failed"); } } /** * Tests object equality. * * @param o1 object 1 * @param o2 object 2 * @throws HubTestException unless <code>o1</code> and <code>o2</code> are both <code>null</code> * or are equal in the sense of {@link java.lang.Object#equals} */ private void assertEquals(Object o1, Object o2) throws HubTestException { if (o1 == null && o2 == null) { } else if (o1 == null || !o1.equals(o2)) { throw new HubTestException("Hub test failed: " + o1 + " != " + o2); } } /** * Tests integer equality. * * @param i1 integer 1 * @param i2 integer 2 * @throws HubTestException iff <code>i1</code> != <code>i2</code> */ private void assertEquals(int i1, int i2) throws HubTestException { if (i1 != i2) { throw new HubTestException("Hub test failed: " + i1 + " != " + i2); } } /** * Utility method to produce an argument list for the CALC_MSG message. * * @param op operation name * @param value operand * @return argument list */ private static List calcArgs(String op, int value) { return Arrays.asList(new Object[] {op, new Integer(value)}); } /** * Utility method to produce a URI->Integer map. * * @param ids array of URIs * @param values array of integer values (same length as <code>ids</code>) * @return URI->Integer map */ private static Map intMap(URI[] ids, int[] values) { Map map = new HashMap(); for (int i = 0; i < ids.length; i++) { map.put(ids[i], new Integer(values[i])); } return map; } /** * Utility method to produce a URI->Object map. * * @param ids array of URIs * @param values array of objects (same length as <code>ids</code>) * @return URI->Object map */ private static Map objMap(URI[] ids, Object[] values) { Map map = new HashMap(); for (int i = 0; i < ids.length; i++) { map.put(ids[i], values[i]); } return map; } /** * Tests the currently running hub. * * @throws HubTestException if the hub is faulty, or if no hub is running */ public static void testHub() throws HubTestException { PlasticHubListener rmiHub; PlasticHubListener xmlrpcHub; try { rmiHub = PlasticUtils.getLocalHub(); xmlrpcHub = new XmlRpcHub(PlasticUtils.getXmlRpcUrl(), rmiHub); } catch (IOException e) { throw new HubTestException("Trouble acquiring hub", e); } testHub(rmiHub); testHub(xmlrpcHub); testHub(rmiHub); } /** * Tests a given hub object. * * @throws HubTestException if the hub is faulty */ public static void testHub(PlasticHubListener hub) throws HubTestException { HubTester htest = new HubTester(hub); try { htest.exerciseHub(); } finally { htest.dispose(); } } /** * Runs tests on a currently running hub. * * <h2>Flags</h2> * * <dl> * <dt>-help * <dd>Prints a help message and exits. * </dl> * * @throws HubTestException if no hub is running, or if the hub fails any of the tests */ public static void main(String[] args) throws HubTestException { String usage = "\nUsage:" + "\n " + HubTester.class.getName() + "\n"; if (args.length == 1 && args[0].startsWith("-h")) { System.out.println(usage); return; } else if (args.length > 0) { System.err.println(usage); System.exit(1); } try { testHub(); System.exit(0); } catch (Throwable error) { error.printStackTrace(); System.exit(1); } } /** PlasticApplication which performs some simple arithmetic. */ private class Counter implements PlasticApplication { private int sum_; private int nreq_; private Throwable error_; public String getName() { return "counter"; } public URI[] getSupportedMessages() { return new URI[] {CALC_MSG}; } public Object perform(URI sender, URI message, List args) { try { if (message.equals(CALC_MSG)) { String mode = (String) args.get(0); int value = ((Integer) args.get(1)).intValue(); assertEquals(2, args.size()); if (mode.equals(PLUS)) { sum_ += value; } else if (mode.equals(MINUS)) { sum_ -= value; } else { throw new HubTestException("Mangled mode \"" + mode + "\"?"); } } nreq_++; synchronized (lock_) { lock_.notifyAll(); } return new Integer(sum_); } catch (Throwable error) { error_ = error; return new Integer(sum_); } } public void dispose() throws HubTestException { if (error_ != null) { throw new HubTestException("Deferred error from client: " + error_.getMessage(), error_); } } } }