You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by rg...@apache.org on 2007/03/13 13:21:37 UTC
svn commit: r517664 - in
/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid:
interop/ interop/coordinator/ interop/old/ interop/testclient/
interop/testclient/testcases/ util/
Author: rgreig
Date: Tue Mar 13 05:21:36 2007
New Revision: 517664
URL: http://svn.apache.org/viewvc?view=rev&rev=517664
Log:
Skeleton of interop testing code added.
Added:
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Listener.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Publisher.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/InteropClientTestCase.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase2BasicP2P.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java
Removed:
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/Listener.java
incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/Publisher.java
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.coordinator;
+
+import java.util.Collection;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.util.ConversationHelper;
+
+/**
+ * An CoordinatingTestCase is a JUnit test case extension that knows how to coordinate test clients that take part in a
+ * test case as defined in the interop testing specification
+ * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification).
+ *
+ * <p/>The real logic of the test cases built on top of this, is embeded in the comparison of the sender and receiver
+ * reports. An example test method might look like:
+ *
+ * <p/><pre>
+ * public void testExample()
+ * {
+ * Properties testConfig = new Properties();
+ * testConfig.add("TEST_CASE", "example");
+ * ...
+ *
+ * Report[] reports = sequenceTest(testConfig);
+ *
+ * // Compare sender and receiver reports.
+ * if (report[0] ... report[1] ...)
+ * {
+ * Assert.fail("Sender and receiver reports did not match up.");
+ * }
+ * }
+ *
+ * </pre>
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Coordinate the test sequence amongst participants. <td> {@link ConversationHelper}
+ * </table>
+ */
+public abstract class CoordinatingTestCase extends TestCase
+{
+ /**
+ *
+ * @param sender The contact details of the sending client in the test.
+ * @param receiver The contact details of the sending client in the test.
+ * @param allClients The list of all possible test clients that may accept the invitation.
+ * @param testProperties The test case definition.
+ */
+ public CoordinatingTestCase(TestClientDetails sender, TestClientDetails receiver,
+ Collection<TestClientDetails> allClients, Properties testProperties)
+ { }
+
+ /**
+ * Holds a test coordinating conversation with the test clients. This is the basic implementation of the inner
+ * loop of Use Case 5. It consists of assign the test roles, begining the test and gathering the test reports
+ * from the participants.
+ *
+ * @param sender The contact details of the sending client in the test.
+ * @param receiver The contact details of the receiving client in the test.
+ * @param allParticipatingClients The list of all clients accepted the invitation.
+ * @param testProperties The test case definition.
+ *
+ * @return The test results from the senders and receivers.
+ */
+ protected Object[] sequenceTest(TestClientDetails sender, TestClientDetails receiver,
+ Collection<TestClientDetails> allParticipatingClients, Properties testProperties)
+ {
+ // Check if the sender and recevier did not accept the invite to this test.
+ {
+ // Automatically fail this combination of sender and receiver.
+ }
+
+ // Assign the sender role to the sending test client.
+
+ // Assign the receiver role the receiving client.
+
+ // Wait for the senders and receivers to confirm their roles.
+
+ // Start the test.
+
+ // Wait for the test sender to return its report.
+
+ // As the receiver for its report.
+
+ // Wait for the receiver to send its report.
+
+ return null;
+ }
+
+ /*protected void setUp()
+ { }*/
+
+ /*protected void tearDown()
+ { }*/
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.coordinator;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.apache.qpid.util.CommandLineParser;
+
+import uk.co.thebadgerset.junit.extensions.TestRunnerImprovedErrorHandling;
+
+/**
+ * <p/>Implements the coordinator client described in the interop testing specification
+ * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). This coordinator is built on
+ * top of the JUnit testing framework.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Find out what test clients are available.
+ * <tr><td> Decorate available tests to run all available clients.
+ * <tr><td> Attach XML test result logger.
+ * <tr><td> Terminate the interop testing framework.
+ * </table>
+ */
+public class Coordinator extends TestRunnerImprovedErrorHandling
+{
+ /** Holds the URL of the broker to coordinate the tests on. */
+ String brokerUrl;
+
+ /** Holds the virtual host to coordinate the tests on. If <tt>null</tt>, then the default virtual host is used. */
+ String virtualHost;
+
+ /**
+ * Creates an interop test coordinator on the specified broker and virtual host.
+ *
+ * @param brokerUrl The URL of the broker to connect to.
+ * @param virtualHost The virtual host to run all tests on. Optional, may be <tt>null</tt>.
+ */
+ Coordinator(String brokerUrl, String virtualHost)
+ {
+ // Retain the connection parameters.
+ this.brokerUrl = brokerUrl;
+ this.virtualHost = virtualHost;
+ }
+
+ /**
+ * The entry point for the interop test coordinator. This client accepts the following command line arguments:
+ *
+ * <p/><table>
+ * <tr><td> -b <td> The broker URL. <td> Mandatory.
+ * <tr><td> -h <td> The virtual host. <td> Optional.
+ * <tr><td> name=value <td> Trailing argument define name/value pairs. Added to system properties. <td> Optional.
+ * </table>
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args)
+ {
+ // Use the command line parser to evaluate the command line.
+ CommandLineParser commandLine =
+ new CommandLineParser(new String[][]
+ {
+ { "b", "The broker URL.", "broker", "true" },
+ { "h", "The virtual host to use.", "virtual host", "false" }
+ });
+
+ // Capture the command line arguments or display errors and correct usage and then exit.
+ Properties options = null;
+
+ try
+ {
+ options = commandLine.parseCommandLine(args);
+ }
+ catch (IllegalArgumentException e)
+ {
+ System.out.println(commandLine.getErrors());
+ System.out.println(commandLine.getUsage());
+ System.exit(1);
+ }
+
+ // Extract the command line options.
+ String brokerUrl = options.getProperty("b");
+ String virtualHost = options.getProperty("h");
+
+ // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up
+ // overridden values from there.
+ commandLine.addCommandLineToSysProperties();
+
+ // Scan for available test cases using a classpath scanner.
+ String[] testClassNames = null;
+
+ // Create a coordinator and begin its test procedure.
+ try
+ {
+ Coordinator coordinator = new Coordinator(brokerUrl, virtualHost);
+ TestResult testResult = coordinator.start(testClassNames);
+
+ if (!testResult.wasSuccessful())
+ {
+ System.exit(FAILURE_EXIT);
+ }
+ else
+ {
+ System.exit(SUCCESS_EXIT);
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ System.exit(EXCEPTION_EXIT);
+ }
+ }
+
+ public TestResult start(String[] testClassNames) throws Exception
+ {
+ // Connect to the broker.
+
+ // Broadcast the compulsory invitation to find out what clients are available to test.
+
+ // Wait for a short time, to give test clients an opportunity to reply to the invitation.
+
+ // Retain the list of all available clients.
+
+ // Run all of the tests in the suite using JUnit.
+ TestResult result = super.start(testClassNames);
+
+ // At this point in time, all tests have completed. Broadcast the shutdown message.
+
+ return result;
+ }
+
+ /**
+ * Runs a test or suite of tests, using the super class implemenation. This method wraps the test to be run
+ * in any test decorators needed to add in the configured toolkits enhanced junit functionality.
+ *
+ * @param test The test to run.
+ * @param wait Undocumented. Nothing in the JUnit javadocs to say what this is for.
+ *
+ * @return The results of the test run.
+ */
+ public TestResult doRun(Test test, boolean wait)
+ {
+ // Combine together the available test cases and test clients to produce a complete list of test case instances
+ // to run as a JUnit test suite.
+
+ return null;
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.coordinator;
+
+/**
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * </table>
+ */
+public class TestClientDetails
+{
+ /** The test clients name. */
+
+ /* The test clients unqiue sequence number. Not currently used. */
+
+ /** The routing key of the test clients control topic. */
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Listener.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Listener.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Listener.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Listener.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,291 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.old;
+
+import java.util.Random;
+
+import javax.jms.*;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.NDC;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * Listener implements the listening end of the Qpid interop tests. It is capable of being run as a standalone listener
+ * that responds to the test messages send by the publishing end of the tests implemented by {@link org.apache.qpid.interop.old.Publisher}.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Count messages received on a topic. <td> {@link org.apache.qpid.interop.old.Publisher}
+ * <tr><td> Send reports on messages received, when requested to. <td> {@link org.apache.qpid.interop.old.Publisher}
+ * <tr><td> Shutdown, when requested to. <td> {@link org.apache.qpid.interop.old.Publisher}
+ * <tr><td>
+ *
+ * @todo This doesn't implement the interop test spec yet. Its a port of the old topic tests but has been adapted with
+ * interop spec in mind.
+ *
+ * @todo I've added lots of field table types in the report message, just to check if the other end can decode them
+ * correctly. Not really the right place to test this, so remove them from {@link #sendReport()} once a better
+ * test exists.
+ */
+public class Listener implements MessageListener
+{
+ private static Logger log = Logger.getLogger(Listener.class);
+
+ /** The default AMQ connection URL to use for tests. */
+ public static final String DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
+
+ /** Holds the name of (routing key for) the topic to receive test messages on. */
+ public static final String CONTROL_TOPIC = "topic_control";
+
+ /** Holds the name of (routing key for) the queue to send reports to. */
+ public static final String RESPONSE_QUEUE = "response";
+
+ /** Holds the JMS Topic to receive test messages on. */
+ private final Topic _topic;
+
+ /** Holds the JMS Queue to send reports to. */
+ private final Queue _response;
+
+ /** Holds the connection to listen on. */
+ private final Connection _connection;
+
+ /** Holds the producer to send control messages on. */
+ private final MessageProducer _controller;
+
+ /** Holds the JMS session. */
+ private final javax.jms.Session _session;
+
+ /** Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. */
+ private boolean init;
+
+ /** Holds the count of messages received by this listener. */
+ private int count;
+
+ /** Used to hold the start time of the first message. */
+ private long start;
+
+ /**
+ * Creates a topic listener using the specified broker URL.
+ *
+ * @param connectionUrl The broker URL to listen on.
+ *
+ * @throws AMQException If the broker connection cannot be established.
+ * @throws URLSyntaxException If the broker URL syntax is not correct.
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ Listener(String connectionUrl) throws AMQException, JMSException, URLSyntaxException
+ {
+ log.debug("Listener(String connectionUrl = " + connectionUrl + "): called");
+
+ // Create a connection to the broker.
+ _connection = new AMQConnection(connectionUrl);
+
+ // Establish a session on the broker.
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Set up the destinations to listen for test and control messages on.
+ _topic = _session.createTopic(CONTROL_TOPIC);
+ _response = _session.createQueue(RESPONSE_QUEUE);
+
+ // Set this listener up to listen for incoming messages on the test topic.
+ _session.createConsumer(_topic).setMessageListener(this);
+
+ // Set up this listener with a producer to send the reports on.
+ _controller = _session.createProducer(_response);
+
+ _connection.start();
+ System.out.println("Waiting for messages...");
+ }
+
+ /**
+ * Starts a test subscriber. The broker URL must be specified as the first command line argument.
+ *
+ * @param argv The command line arguments, ignored.
+ *
+ * @todo Add command line arguments to configure all aspects of the test.
+ */
+ public static void main(String[] argv)
+ {
+ try
+ {
+ new Listener(DEFAULT_URI);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Handles all message received by this listener. Test messages are counted, report messages result in a report being sent and
+ * shutdown messages result in this listener being terminated.
+ *
+ * @param message The received message.
+ */
+ public void onMessage(Message message)
+ {
+ log.debug("public void onMessage(Message message = " + message + "): called");
+
+ // Take the start time of the first message if this is the first message.
+ if (!init)
+ {
+ start = System.nanoTime() / 1000000;
+ count = 0;
+ init = true;
+ }
+
+ try
+ {
+ // Check if the message is a control message telling this listener to shut down.
+ if (isShutdown(message))
+ {
+ log.debug("Got a shutdown message.");
+ shutdown();
+ }
+ // Check if the message is a report request message asking this listener to respond with the message count.
+ else if (isReport(message))
+ {
+ log.debug("Got a report request message.");
+
+ // Send the message count report.
+ sendReport();
+
+ // Reset the initialization flag so that the next message is considered to be the first.
+ init = false;
+ }
+ // Otherwise it is an ordinary test message, so increment the message count.
+ else
+ {
+ count++;
+ }
+ }
+ catch (JMSException e)
+ {
+ log.warn("There was a JMSException during onMessage.", e);
+ }
+ }
+
+ /**
+ * Checks a message to see if it is a termination request control message.
+ *
+ * @param m The message to check.
+ *
+ * @return <tt>true</tt> if it is a termination request control message, <tt>false</tt> otherwise.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ boolean isShutdown(Message m) throws JMSException
+ {
+ boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST");
+
+ return result;
+ }
+
+ /**
+ * Checks a message to see if it is a report request control message.
+ *
+ * @param m The message to check.
+ *
+ * @return <tt>true</tt> if it is a report request control message, <tt>false</tt> otherwise.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ boolean isReport(Message m) throws JMSException
+ {
+ boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST");
+
+ return result;
+ }
+
+ /**
+ * Checks whether or not a text field on a message has the specified value.
+ *
+ * @param m The message to check.
+ * @param fieldName The name of the field to check.
+ * @param value The expected value of the field to compare with.
+ *
+ * @return <tt>true</tt>If the specified field has the specified value, <tt>fals</tt> otherwise.
+ *
+ * @throws JMSException Any JMSExceptions are allowed to fall through.
+ */
+ private static boolean checkTextField(Message m, String fieldName, String value) throws JMSException
+ {
+ //log.debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName
+ // + ", String value = " + value + "): called");
+
+ String comp = m.getStringProperty(fieldName);
+ //log.debug("comp = " + comp);
+
+ boolean result = (comp != null) && comp.equals(value);
+ //log.debug("result = " + result);
+
+ return result;
+ }
+
+ /**
+ * Closes down the connection to the broker.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ private void shutdown() throws JMSException
+ {
+ _session.close();
+ _connection.stop();
+ _connection.close();
+ }
+
+ /**
+ * Send the report message to the response queue.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ private void sendReport() throws JMSException
+ {
+ log.debug("private void report(): called");
+
+ // Create the report message.
+ long time = ((System.nanoTime() / 1000000) - start);
+ String msg = "Received " + count + " in " + time + "ms";
+ Message message = _session.createTextMessage(msg);
+
+ // Shove some more field table types in the message just to see if the other end can handle it.
+ message.setBooleanProperty("BOOLEAN", true);
+ //message.setByteProperty("BYTE", (byte) 5);
+ message.setDoubleProperty("DOUBLE", Math.PI);
+ message.setFloatProperty("FLOAT", 1.0f);
+ message.setIntProperty("INT", 1);
+ message.setShortProperty("SHORT", (short) 1);
+ message.setLongProperty("LONG", (long) 1827361278);
+ message.setStringProperty("STRING", "hello");
+
+ // Send the report message.
+ _controller.send(message);
+ log.debug("Sent report: " + msg);
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Publisher.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Publisher.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Publisher.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/old/Publisher.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,244 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.old;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.*;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * Publisher is the sending end of Qpid interop tests. It is capable of being run as a standalone publisher
+ * that sends test messages to the listening end of the tests implemented by {@link org.apache.qpid.interop.old.Listener}.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ *
+ * @todo This doesn't implement the interop test spec yet. Its a port of the old topic tests but has been adapted with
+ * interop spec in mind.
+ *
+ * @todo I've added lots of field table types in the report request message, just to check if the other end can decode
+ * them correctly. Not really the right place to test this, so remove them from {@link #doTest()} once a better
+ * test exists.
+ */
+public class Publisher implements MessageListener
+{
+ private static Logger log = Logger.getLogger(Publisher.class);
+
+ /** The default AMQ connection URL to use for tests. */
+ public static final String DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
+
+ /** Holds the default test timeout for broker communications before tests give up. */
+ public static final int TIMEOUT = 3000;
+
+ /** Holds the routing key for the topic to send test messages on. */
+ public static final String CONTROL_TOPIC = "topic_control";
+
+ /** Holds the routing key for the queue to receive reports on. */
+ public static final String RESPONSE_QUEUE = "response";
+
+ /** Holds the JMS Topic to send test messages on. */
+ private final Topic _topic;
+
+ /** Holds the JMS Queue to receive reports on. */
+ private final Queue _response;
+
+ /** Holds the number of messages to send in each test run. */
+ private int numMessages;
+
+ /** A monitor used to wait for all reports to arrive back from consumers on. */
+ private CountDownLatch allReportsReceivedEvt;
+
+ /** Holds the connection to listen on. */
+ private Connection _connection;
+
+ /** Holds the channel for all test messages.*/
+ private Session _session;
+
+ /** Holds the producer to send test messages on. */
+ private MessageProducer publisher;
+
+ /**
+ * Creates a topic publisher that will send the specifed number of messages and expect the specifed number of report back from test
+ * subscribers.
+ *
+ * @param connectionUri The broker URL.
+ * @param numMessages The number of messages to send in each test.
+ * @param numSubscribers The number of subscribes that are expected to reply with a report.
+ */
+ Publisher(String connectionUri, int numMessages, int numSubscribers)
+ throws AMQException, JMSException, URLSyntaxException
+ {
+ log.debug("Publisher(String connectionUri = " + connectionUri + ", int numMessages = " + numMessages
+ + ", int numSubscribers = " + numSubscribers + "): called");
+
+ // Create a connection to the broker.
+ _connection = new AMQConnection(connectionUri);
+
+ // Establish a session on the broker.
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Set up the destinations to send test messages and listen for reports on.
+ _topic = _session.createTopic(CONTROL_TOPIC);
+ _response = _session.createQueue(RESPONSE_QUEUE);
+
+ // Set this listener up to listen for reports on the response queue.
+ _session.createConsumer(_response).setMessageListener(this);
+
+ // Set up this listener with a producer to send the test messages and report requests on.
+ publisher = _session.createProducer(_topic);
+
+ // Keep the test parameters.
+ this.numMessages = numMessages;
+
+ // Set up a countdown to count all subscribers sending their reports.
+ allReportsReceivedEvt = new CountDownLatch(numSubscribers);
+
+ _connection.start();
+ System.out.println("Sending messages and waiting for reports...");
+ }
+
+ /**
+ * Start a test publisher. The broker URL must be specified as the first command line argument.
+ *
+ * @param argv The command line arguments, ignored.
+ *
+ * @todo Add command line arguments to configure all aspects of the test.
+ */
+ public static void main(String[] argv)
+ {
+ try
+ {
+ // Create an instance of this publisher with the command line parameters.
+ Publisher publisher = new Publisher(DEFAULT_URI, 1, 1);
+
+ // Publish the test messages.
+ publisher.doTest();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sends the test messages and waits for all subscribers to reply with a report.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ public void doTest() throws JMSException
+ {
+ log.debug("public void DoTest(): called");
+
+ // Create a test message to send.
+ Message testMessage = _session.createTextMessage("test");
+
+ // Send the desired number of test messages.
+ for (int i = 0; i < numMessages; i++)
+ {
+ publisher.send(testMessage);
+ }
+
+ log.debug("Sent " + numMessages + " test messages.");
+
+ // Send the report request.
+ Message reportRequestMessage = _session.createTextMessage("Report request message.");
+ reportRequestMessage.setStringProperty("TYPE", "REPORT_REQUEST");
+
+ reportRequestMessage.setBooleanProperty("BOOLEAN", false);
+ //reportRequestMessage.Headers.SetByte("BYTE", 5);
+ reportRequestMessage.setDoubleProperty("DOUBLE", 3.141);
+ reportRequestMessage.setFloatProperty("FLOAT", 1.0f);
+ reportRequestMessage.setIntProperty("INT", 1);
+ reportRequestMessage.setLongProperty("LONG", 1);
+ reportRequestMessage.setStringProperty("STRING", "hello");
+ reportRequestMessage.setShortProperty("SHORT", (short) 2);
+
+ publisher.send(reportRequestMessage);
+
+ log.debug("Sent the report request message, waiting for all replies...");
+
+ // Wait until all the reports come in.
+ try
+ {
+ allReportsReceivedEvt.await(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ { }
+
+ // Check if all reports were really received or if the timeout occurred.
+ if (allReportsReceivedEvt.getCount() == 0)
+ {
+ log.debug("Got all reports.");
+ }
+ else
+ {
+ log.debug("Waiting for reports timed out, still waiting for " + allReportsReceivedEvt.getCount() + ".");
+ }
+
+ // Send the termination request.
+ Message terminationRequestMessage = _session.createTextMessage("Termination request message.");
+ terminationRequestMessage.setStringProperty("TYPE", "TERMINATION_REQUEST");
+ publisher.send(terminationRequestMessage);
+
+ log.debug("Sent the termination request message.");
+
+ // Close all message producers and consumers and the connection to the broker.
+ shutdown();
+ }
+
+ /**
+ * Handles all report messages from subscribers. This decrements the count of subscribers that are still to reply, until this becomes
+ * zero, at which time waiting threads are notified of this event.
+ *
+ * @param message The received report message.
+ */
+ public void onMessage(Message message)
+ {
+ log.debug("public void OnMessage(Message message = " + message + "): called");
+
+ // Decrement the count of expected messages and release the wait monitor when this becomes zero.
+ allReportsReceivedEvt.countDown();
+
+ if (allReportsReceivedEvt.getCount() == 0)
+ {
+ log.debug("Got reports from all subscribers.");
+ }
+ }
+
+ /**
+ * Stops the message consumers and closes the connection.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ private void shutdown() throws JMSException
+ {
+ _session.close();
+ _connection.close();
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/InteropClientTestCase.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/InteropClientTestCase.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/InteropClientTestCase.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/InteropClientTestCase.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.testclient;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+
+/**
+ * InteropClientTestCase provides an interface that classes implementing test cases from the interop testing spec
+ * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification) should implement. Implementations
+ * must be Java beans, that is, to provide a default constructor and to implement the {@link #getName} method.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Supply the name of the test case that this implements.
+ * <tr><td> Accept/Reject invites based on test parameters.
+ * <tr><td> Adapt to assigned roles.
+ * <tr><td> Perform test case actions.
+ * <tr><td> Generate test reports.
+ * </table>
+ */
+public interface InteropClientTestCase extends MessageListener
+{
+ /** Defines the possible test case roles that an interop test case can take on. */
+ public enum Roles
+ {
+ SENDER, RECEIVER;
+ }
+
+ /**
+ * Should provide the name of the test case that this class implements. The exact names are defined in the
+ * interop testing spec.
+ *
+ * @return The name of the test case that this implements.
+ */
+ public String getName();
+
+ /**
+ * Determines whether the test invite that matched this test case is acceptable.
+ *
+ * @param inviteMessage The invitation to accept or reject.
+ *
+ * @return <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public boolean acceptInvite(Message inviteMessage) throws JMSException;
+
+ /**
+ * Assigns the role to be played by this test case. The test parameters are fully specified in the
+ * assignment message. When this method return the test case will be ready to execute.
+ *
+ * @param role The role to be played; sender or receiver.
+ * @param assignRoleMessage The role assingment message, contains the full test parameters.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public void assignRole(Roles role, Message assignRoleMessage) throws JMSException;
+
+ /**
+ * Performs the test case actions.
+ */
+ public void start();
+
+ /**
+ * Gets a report on the actions performed by the test case in its assigned role.
+ *
+ * @param session The session to create the report message in.
+ *
+ * @return The report message.
+ *
+ * @throws JMSException Any JMSExceptions resulting from creating the report are allowed to fall through.
+ */
+ public Message getReport(Session session) throws JMSException;
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,213 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.testclient;
+
+import java.util.Properties;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.apache.qpid.util.CommandLineParser;
+
+/**
+ * Implements a test client as described in the interop testing spec
+ * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). A test client is an agent that
+ * reacts to control message sequences send by the test {@link org.apache.qpid.interop.coordinator.Coordinator}.
+ *
+ * <p/><table><caption>Messages Handled by TestClient</caption>
+ * <tr><th> Message <th> Action
+ * <tr><td> Invite(compulsory) <td> Reply with Enlist.
+ * <tr><td> Invite(test case) <td> Reply with Enlist if test case available.
+ * <tr><td> AssignRole(test case) <td> Reply with Accept Role if matches an enlisted test. Keep test parameters.
+ * <tr><td> Start <td> Send test messages defined by test parameters. Send report on messages sent.
+ * <tr><td> Status Request <td> Send report on messages received.
+ * </table>
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Handle all incoming control messages. <td> {@link InteropClientTestCase}
+ * <tr><td> Configure and look up test cases by name. <td> {@link InteropClientTestCase}
+ * </table>
+ */
+public class TestClient implements MessageListener
+{
+ /** Holds the URL of the broker to run the tests on. */
+ String brokerUrl;
+
+ /** Holds the virtual host to run the tests on. If <tt>null</tt>, then the default virtual host is used. */
+ String virtualHost;
+
+ /** Defines an enumeration of the control message types and handling behaviour for each. */
+ protected enum ControlMessages implements MessageListener
+ {
+ INVITE_COMPULSORY
+ {
+ public void onMessage(Message message)
+ {
+ // Reply with the client name in an Enlist message.
+ }
+ },
+ INVITE
+ {
+ public void onMessage(Message message)
+ {
+ // Extract the test properties.
+
+ // Check if the requested test case is available.
+ {
+ // Make the requested test case the current test case.
+
+ // Reply by accepting the invite in an Enlist message.
+ }
+ }
+ },
+ ASSIGN_ROLE
+ {
+ public void onMessage(Message message)
+ {
+ // Extract the test properties.
+
+ // Reply by accepting the role in an Accept Role message.
+ }
+ },
+ START
+ {
+ public void onMessage(Message message)
+ {
+ // Start the current test case.
+
+ // Generate the report from the test case and reply with it as a Report message.
+ }
+ },
+ STATUS_REQUEST
+ {
+ public void onMessage(Message message)
+ {
+ // Generate the report from the test case and reply with it as a Report message.
+ }
+ },
+ UNKNOWN
+ {
+ public void onMessage(Message message)
+ {
+ // Log a warning about this but otherwise ignore it.
+ }
+ };
+
+ /**
+ * Handles control messages appropriately depending on the message type.
+ *
+ * @param message The incoming message to handle.
+ */
+ public abstract void onMessage(Message message);
+ }
+
+ public TestClient(String brokerUrl, String virtualHost)
+ {
+ // Retain the connection parameters.
+ this.brokerUrl = brokerUrl;
+ this.virtualHost = virtualHost;
+ }
+
+ /**
+ * The entry point for the interop test coordinator. This client accepts the following command line arguments:
+ *
+ * <p/><table>
+ * <tr><td> -b <td> The broker URL. <td> Mandatory.
+ * <tr><td> -h <td> The virtual host. <td> Optional.
+ * <tr><td> name=value <td> Trailing argument define name/value pairs. Added to system properties. <td> Optional.
+ * </table>
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args)
+ {
+ // Use the command line parser to evaluate the command line.
+ CommandLineParser commandLine =
+ new CommandLineParser(new String[][]
+ {
+ { "b", "The broker URL.", "broker", "true" },
+ { "h", "The virtual host to use.", "virtual host", "false" }
+ });
+
+ // Capture the command line arguments or display errors and correct usage and then exit.
+ Properties options = null;
+
+ try
+ {
+ options = commandLine.parseCommandLine(args);
+ }
+ catch (IllegalArgumentException e)
+ {
+ System.out.println(commandLine.getErrors());
+ System.out.println(commandLine.getUsage());
+ System.exit(1);
+ }
+
+ // Extract the command line options.
+ String brokerUrl = options.getProperty("b");
+ String virtualHost = options.getProperty("h");
+
+ // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up
+ // overridden values from there.
+ commandLine.addCommandLineToSysProperties();
+
+ // Create a test client and start it running.
+ TestClient client = new TestClient(brokerUrl, virtualHost);
+ client.start();
+ }
+
+ private void start()
+ {
+ // Use a class path scanner to find all the interop test case implementations.
+
+ // Create all the test case implementations and index them by the test names.
+
+ // Open a connection to communicate with the coordinator on.
+
+ // Set this up to listen for control messages.
+
+ // Create a producer to send replies with.
+ }
+
+ /**
+ * Handles all incoming control messages.
+ *
+ * @param message The incoming message.
+ */
+ public void onMessage(Message message)
+ {
+ // Delegate the message handling to the message type specific handler.
+ extractMessageType(message).onMessage(message);
+ }
+
+ /**
+ * Determines the control messsage type of incoming messages.
+ *
+ * @param message The message to determine the type of.
+ *
+ * @return The control message type of the message.
+ */
+ protected ControlMessages extractMessageType(Message message)
+ {
+ return null;
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.testclient.testcases;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.apache.qpid.interop.testclient.InteropClientTestCase;
+
+/**
+ * Implements tet case 1, dummy run. This test case sends no test messages, it exists to confirm that the test harness
+ * is interacting with the coordinator correctly.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Supply the name of the test case that this implements.
+ * <tr><td> Accept/Reject invites based on test parameters.
+ * <tr><td> Adapt to assigned roles.
+ * <tr><td> Perform test case actions.
+ * <tr><td> Generate test reports.
+ * </table>
+ */
+public class TestCase1DummyRun implements InteropClientTestCase
+{
+ public String getName()
+ {
+ return "TC1_DummyRun";
+ }
+
+ public boolean acceptInvite(Message inviteMessage) throws JMSException
+ {
+ // Test parameters don't matter, accept all invites.
+ return true;
+ }
+
+ public void assignRole(Roles role, Message assignRoleMessage) throws JMSException
+ {
+ // Do nothing, both roles are the same.
+ }
+
+ public void start()
+ {
+ // Do nothing.
+ }
+
+ public Message getReport(Session session) throws JMSException
+ {
+ // Generate a dummy report, the coordinator expects a report but doesn't care what it is.
+ return session.createTextMessage("Dummy Run, Ok.");
+ }
+
+ public void onMessage(Message message)
+ {
+ // Ignore any messages.
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase2BasicP2P.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase2BasicP2P.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase2BasicP2P.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase2BasicP2P.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,133 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.interop.testclient.testcases;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.apache.qpid.interop.testclient.InteropClientTestCase;
+
+/**
+ * Implements test case 2, basic P2P. Sends/received a specified number of messages to a specified route on the
+ * default direct exchange. Produces reports on the actual number of messages sent/received.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Supply the name of the test case that this implements.
+ * <tr><td> Accept/Reject invites based on test parameters.
+ * <tr><td> Adapt to assigned roles.
+ * <tr><td> Send required number of test messages.
+ * <tr><td> Generate test reports.
+ * </table>
+ */
+public class TestCase2BasicP2P implements InteropClientTestCase
+{
+ /**
+ * Should provide the name of the test case that this class implements. The exact names are defined in the
+ * interop testing spec.
+ *
+ * @return The name of the test case that this implements.
+ */
+ public String getName()
+ {
+ return "TC2_BasicP2P";
+ }
+
+ /**
+ * Determines whether the test invite that matched this test case is acceptable.
+ *
+ * @param inviteMessage The invitation to accept or reject.
+ *
+ * @return <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public boolean acceptInvite(Message inviteMessage) throws JMSException
+ {
+ // All invites are acceptable.
+ return true;
+ }
+
+ /**
+ * Assigns the role to be played by this test case. The test parameters are fully specified in the
+ * assignment message. When this method return the test case will be ready to execute.
+ *
+ * @param role The role to be played; sender or receiver.
+ *
+ * @param assignRoleMessage The role assingment message, contains the full test parameters.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public void assignRole(Roles role, Message assignRoleMessage) throws JMSException
+ {
+ // Take note of the role to be played.
+
+ // Extract and retain the test parameters.
+
+ // Create a new connection to pass the test messages on.
+
+ // Check if the sender role is being assigned, and set up a message producer if so.
+ {
+ }
+ // Otherwise the receiver role is being assigned, so set this up to listen for messages.
+ {
+ }
+ }
+
+ /**
+ * Performs the test case actions.
+ */
+ public void start()
+ {
+ // Check that the sender role is being performed.
+ {
+ }
+ }
+
+ /**
+ * Gets a report on the actions performed by the test case in its assigned role.
+ *
+ * @param session The session to create the report message in.
+ *
+ * @return The report message.
+ *
+ * @throws JMSException Any JMSExceptions resulting from creating the report are allowed to fall through.
+ */
+ public Message getReport(Session session) throws JMSException
+ {
+ // Close the test connection.
+
+ // Generate a report message containing the count of the number of messages passed.
+
+ return null;
+ }
+
+ /**
+ * Counts incoming test messages.
+ *
+ * @param message The incoming test message.
+ */
+ public void onMessage(Message message)
+ {
+ // Increment the message count.
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * An ClasspathScanner scans the classpath for classes that implement an interface or extend a base class and have names
+ * that match a regular expression.
+ *
+ * <p/>In order to test whether a class implements an interface or extends a class, the class must be loaded (unless
+ * the class files were to be scanned directly). Using this collector can cause problems when it scans the classpath,
+ * because loading classes will initialize their statics, which in turn may cause undesired side effects. For this
+ * reason, the collector should always be used with a regular expression, through which the class file names are
+ * filtered, and only those that pass this filter will be tested. For example, if you define tests in classes that
+ * end with the keyword "Test" then use the regular expression "Test$" to match this.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Find all classes matching type and name pattern on the classpath.
+ * </table>
+ */
+public class ClasspathScanner
+{
+ static final int SUFFIX_LENGTH = ".class".length();
+
+ /**
+ * Scans the classpath and returns all classes that extend a specified class and match a specified name.
+ * There is an flag that can be used to indicate that only Java Beans will be matched (that is, only those classes
+ * that have a default constructor).
+ *
+ * @param matchingClass The class or interface to match.
+ * @param matchingRegexp The reular expression to match against the class name.
+ * @param beanOnly Flag to indicate that onyl classes with default constructors should be matched.
+ *
+ * @return All the classes that match this collector.
+ */
+ public static Collection<Class<?>> getMatches(Class<?> matchingClass, String matchingRegexp, boolean beanOnly)
+ {
+ String classPath = System.getProperty("java.class.path");
+ Map result = new HashMap();
+
+ for (String path : splitClassPath(classPath))
+ {
+ gatherFiles(new File(path), "", result);
+ }
+
+ return result.values();
+ }
+
+ private static void gatherFiles(File classRoot, String classFileName, Map result)
+ {
+ File thisRoot = new File(classRoot, classFileName);
+
+ if (thisRoot.isFile())
+ {
+ if (matchesName(classFileName))
+ {
+ String className = classNameFromFile(classFileName);
+ result.put(className, className);
+ }
+
+ return;
+ }
+
+ String[] contents = thisRoot.list();
+
+ if (contents != null)
+ {
+ for (String content : contents)
+ {
+ gatherFiles(classRoot, classFileName + File.separatorChar + content, result);
+ }
+ }
+ }
+
+ private static boolean matchesName(String classFileName)
+ {
+ return classFileName.endsWith(".class") && (classFileName.indexOf('$') < 0) && (classFileName.indexOf("Test") > 0);
+ }
+
+ private static boolean matchesInterface()
+ {
+ return false;
+ }
+
+ /**
+ * Takes a classpath (which is a series of paths) and splits it into its component paths.
+ *
+ * @param classPath The classpath to split.
+ *
+ * @return A list of the component paths that make up the class path.
+ */
+ private static List<String> splitClassPath(String classPath)
+ {
+ List<String> result = new LinkedList<String>();
+ String separator = System.getProperty("path.separator");
+ StringTokenizer tokenizer = new StringTokenizer(classPath, separator);
+
+ while (tokenizer.hasMoreTokens())
+ {
+ result.add(tokenizer.nextToken());
+ }
+
+ return result;
+ }
+
+ /**
+ * convert /a/b.class to a.b
+ *
+ * @param classFileName
+ *
+ * @return
+ */
+ private static String classNameFromFile(String classFileName)
+ {
+
+ String s = classFileName.substring(0, classFileName.length() - SUFFIX_LENGTH);
+ String s2 = s.replace(File.separatorChar, '.');
+ if (s2.startsWith("."))
+ {
+ return s2.substring(1);
+ }
+
+ return s2;
+ }
+}
Added: incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java?view=auto&rev=517664
==============================================================================
--- incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java (added)
+++ incubator/qpid/trunk/qpid/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java Tue Mar 13 05:21:36 2007
@@ -0,0 +1,167 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import java.util.Collection;
+import java.util.Queue;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+/**
+ * A conversation helper, uses a message correlation id pattern to match up sent and received messages as a conversation
+ * over JMS messaging. Incoming message traffic is divided up by correlation id. Each id has a queue (behaviour dependant
+ * on the queue implementation). Clients of this de-multiplexer can wait on messages, defined by message correlation ids.
+ * The correlating listener is a message listener, and can therefore be attached to a MessageConsumer which is consuming
+ * from a queue or topic.
+ *
+ * <p/>One use of the correlating listener is to act as a conversation synchronizer where multiple threads are carrying
+ * out conversations over a multiplexed messaging route. This can be usefull, as JMS sessions are not multi-threaded.
+ * Setting up the correlating listener with synchronous queues will allow these threads to be written in a synchronous
+ * style, but with their execution order governed by the asynchronous message flow. For example, something like the
+ * following code could run a multi-threaded conversation (the conversation methods can be called many times in
+ * parallel):
+ *
+ * <p/><pre>
+ * MessageListener conversation = new ConversationHelper(java.util.concurrent.LinkedBlockingQueue.class),
+ * sendDesitination, replyDestination);
+ *
+ * initiateConversation()
+ * {
+ * try {
+ * // Exchange greetings.
+ * conversation.send(conversation.getSession().createTextMessage("Hello."));
+ * Message greeting = conversation.receive();
+ *
+ * // Exchange goodbyes.
+ * conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ * Message goodbye = conversation.receive();
+ * } finally {
+ * conversation.end();
+ * }
+ * }
+ *
+ * respondToConversation()
+ * {
+ * try {
+ * // Exchange greetings.
+ * Message greeting = conversation.receive();
+ * conversation.send(conversation.getSession().createTextMessage("Hello."));
+ *
+ * // Exchange goodbyes.
+ * Message goodbye = conversation.receive();
+ * conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ * } finally {
+ * conversation.end();
+ * }
+ * }
+ *
+ * </pre>
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><th> Associate messages to a conversation using correlation ids.
+ * <tr><td> Auto manage sessions for conversations.
+ * <tr><td> Store messages not in conversation in dead letter box.
+ * </table>
+ *
+ * @todo Non-transactional, can use shared session. Transactional, must have session per-thread. Session pool? In
+ * transactional mode, commits must happen before receiving, or no replies will come in. (unless there were some
+ * pending on the queue?). Also, having received on a particular session, must ensure that session is used for all
+ * subsequent sends and receive at least until the transaction is committed. So a message selector must be used
+ * to restrict receives on that session to prevent it picking up messages bound for other conversations.
+ *
+ * @todo Want something convenient that hides many details. Write out some example use cases to get the best feel for
+ * it. Pass in connection, send destination, receive destination. Provide endConvo, send, receive
+ * methods. Bind corrId, session etc. on thread locals. Clean on endConvo. Provide deadLetter box, that
+ * uncorrelated or late messages go in. Provide time-out on wait methods, and global time-out.
+ * PingPongProducer provides a good use-case example (sends messages, waits for replies).
+ *
+ * @todo New correlationId on every send? or correlation id per conversation? or callers choice.
+ */
+public class ConversationHelper
+{
+ /**
+ * Creates a conversation helper on the specified connection with the default sending destination, and listening
+ * to the specified receiving destination.
+ *
+ * @param connection The connection to build the conversation helper on.
+ * @param sendDestination The default sending destiation for all messages.
+ * @param receiveDestination The destination to listen to for incoming messages.
+ * @param queueClass The queue implementation class.
+ */
+ public ConversationHelper(Connection connection, Destination sendDestination, Destination receiveDestination,
+ Class<? extends Queue> queueClass)
+ { }
+
+ /**
+ * Sends a message to the default sending location. The correlation id of the message will be assigned by this
+ * method, overriding any previously set value.
+ *
+ * @param message The message to send.
+ */
+ public void send(Message message)
+ { }
+
+ /**
+ * Gets the next message in an ongoing conversation. This method may block until such a message is received.
+ *
+ * @return The next incoming message in the conversation.
+ */
+ public Message receive()
+ {
+ return null;
+ }
+
+ /**
+ * Completes the conversation. Any open transactions are committed. Any correlation id's pertaining to the
+ * conversation are no longer valid, and any incoming messages using them will go to the dead letter box.
+ */
+ public void end()
+ { }
+
+ /**
+ * Clears the dead letter box, returning all messages that were in it.
+ *
+ * @return All messages in the dead letter box.
+ */
+ public Collection<Message> emptyDeadLetterBox()
+ {
+ return null;
+ }
+
+ /**
+ * Implements the message listener for this conversation handler.
+ */
+ protected class Receiver implements MessageListener
+ {
+ /**
+ * Handles all incoming messages in the ongoing conversations. These messages are split up by correaltion id
+ * and placed into queues.
+ *
+ * @param message The incoming message.
+ */
+ public void onMessage(Message message)
+ { }
+ }
+}