summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRupert Smith <rupertlssmith@apache.org>2007-07-13 14:24:03 +0000
committerRupert Smith <rupertlssmith@apache.org>2007-07-13 14:24:03 +0000
commitf4413e24a4d9e829b9c3775d2bd8ad9aaadde56f (patch)
treecff3af10cb9ea6953743e2c848e075060c66247a
parente66ea7a6f8dedd57711c3fa8556c34455dddc21c (diff)
downloadqpid-python-f4413e24a4d9e829b9c3775d2bd8ad9aaadde56f.tar.gz
Moved test framework into its own package and cleaned it up.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/M2@556011 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java30
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java758
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java127
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java39
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java66
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java116
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java77
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java119
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/CircuitImpl.java384
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java123
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java136
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java36
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java (renamed from java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java)2
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/MultiProducerConsumerPairImpl.java82
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java49
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/PublisherImpl.java153
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java42
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/ReceiverImpl.java79
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java108
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/package.html22
20 files changed, 1738 insertions, 810 deletions
diff --git a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
index d5d1c304e9..5d3df1d9ec 100644
--- a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
+++ b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
@@ -20,20 +20,6 @@
*/
package org.apache.qpid.requestreply;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.jms.*;
-
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
@@ -51,6 +37,20 @@ import uk.co.thebadgerset.junit.extensions.BatchedThrottle;
import uk.co.thebadgerset.junit.extensions.Throttle;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+import javax.jms.*;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
/**
* PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may
* either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens
@@ -237,7 +237,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis
/** Holds the default message selector. */
public static final String SELECTOR_DEFAULT = "";
- /** Holds the name of the proeprty to get the destination count from. */
+ /** Holds the name of the property to get the destination count from. */
public static final String DESTINATION_COUNT_PROPNAME = "destinationCount";
/** Defines the default number of destinations to ping. */
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java
index dbe932d015..7d6e7d044c 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java
@@ -20,34 +20,15 @@
*/
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
-
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQNoConsumersException;
-import org.apache.qpid.client.AMQNoRouteException;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.transport.TransportConnection;
-import static org.apache.qpid.server.exchange.MessagingTestConfigProperties.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.CircuitImpl;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
-import javax.jms.*;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
/**
* ImmediateMessageTest tests for the desired behaviour of immediate messages. Immediate messages are a non-JMS
* feature. A message may be marked with an immediate delivery flag, which means that a consumer must be connected
@@ -68,50 +49,38 @@ import java.util.concurrent.atomic.AtomicLong;
* disconnected.
* </table>
*
- * @todo Write a test decorator, the sole function of which is to populate test context properties, from sys properties,
- * from trailing prop=value pairs on the command line, from test properties files or other sources. This should
- * run through stanard JUnit without the JUnit toolkit extensions, and through Maven surefire, and also through
- * the JUnit toolkit extended test runners.
- *
- * @todo Veto test topologies using bounce back. Or else the bounce back client will act as an immediate consumer.
+ * @todo All of these test cases will be generated by a test generator that thoroughly tests all combinations of test
+ * circuits.
*/
-public class ImmediateMessageTest extends TestCase
+public class ImmediateMessageTest extends FrameworkBaseCase
{
- /** Used for debugging. */
- private static final Logger log = LoggerFactory.getLogger(ImmediateMessageTest.class);
-
/** Used to read the tests configurable properties through. */
ParsedProperties testProps;
- /** Used to create unique destination names for each test.
- * @todo Move into the test framework.
- */
- private static AtomicLong uniqueDestsId = new AtomicLong();
-
/** Check that an immediate message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_517_ImmediateOkNoTxP2P() throws Exception
+ public void test_QPID_517_ImmediateOkNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an immediate message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_517_ImmediateOkTxP2P() throws Exception
+ public void test_QPID_517_ImmediateOkTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an immediate message results in no consumers code, not using transactions, when a consumer is disconnected. */
@@ -121,13 +90,13 @@ public class ImmediateMessageTest extends TestCase
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no consumers code, in a transaction, when a consumer is disconnected. */
@@ -137,17 +106,17 @@ public class ImmediateMessageTest extends TestCase
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no consumers code, not using transactions, when no consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteNoTxP2P() throws Exception
+ public void test_QPID_517_ImmediateFailsNoRouteNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -157,14 +126,14 @@ public class ImmediateMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message results in no consumers code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteTxP2P() throws Exception
+ public void test_QPID_517_ImmediateFailsNoRouteTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -174,36 +143,36 @@ public class ImmediateMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_517_ImmediateOkNoTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateOkNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an immediate message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_517_ImmediateOkTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateOkTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an immediate message results in no consumers code, not using transactions, when a consumer is disconnected. */
@@ -216,13 +185,13 @@ public class ImmediateMessageTest extends TestCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no consumers code, in a transaction, when a consumer is disconnected. */
@@ -235,17 +204,17 @@ public class ImmediateMessageTest extends TestCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no consumers code, not using transactions, when no consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteNoTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateFailsNoRouteNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -255,14 +224,14 @@ public class ImmediateMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message results in no consumers code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateFailsNoRouteTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -272,15 +241,15 @@ public class ImmediateMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
protected void setUp() throws Exception
{
- NDC.push(getName());
+ super.setUp();
testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
@@ -290,642 +259,5 @@ public class ImmediateMessageTest extends TestCase
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
-
- // Ensure that the in-vm broker is created.
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- try
- {
- // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
- TransportConnection.killVMBroker(1);
- ApplicationRegistry.remove(1);
- }
- finally
- {
- NDC.pop();
- }
- }
-
- /*
- * Stuff below:
- *
- * This will get tidied into some sort on JMS convenience framework, through which practically any usefull test
- * topology can be created. This will become a replacement for PingPongProducer.
- *
- * Base everything on standard connection properties defined in PingPongProducer. Split JMS and AMQP-only properties.
- *
- * Integrate with ConversationFactory, so that it will work with prod/con pairs.
- *
- * Support pub/rec pairs.
- * Support m*n pub/rec setups. All pubs/recs on one machine.
- *
- * Support bounce back clients, with configurable bounce back behavior. All, one in X, round robin one in m, etc.
- *
- * Support pairing of m*n pub/rec setups with bounce back clients. JVM running a test, can simulate m publishers,
- * will receive (a known subset of) all messages sent, bounced back to n receivers. Co-location of pub/rec will be
- * the normal model to allow accurate timings to be taken.
- *
- * Support creation of pub or rec only.
- * Support clock synching of pub/rec on different JVMs, by calculating clock offsets. Must also provide an accuracy
- * estimate to +- the results.
- *
- * Augment the interop Coordinator, to become a full distributed test coordinator. Capable of querying available
- * tests machines, looking at test parameters and farming out tests onto the test machines, passing all test
- * parameters, standard naming of pub/rec config parameters used to set up m*n test topologies, run test cases,
- * report results, tear down m*n topologies. Need to split the re-usable general purpose distributed test coordinator
- * from the Qpid specific test framework for creating test-topoloigies and passing Qpid specific parameters.
- *
- * Write all tests against pub/rec pairs, without coding to the fact that the topology may be anything from 1:1 in
- * JVM to m*n with bounce back clients accross many machines. That is, make the test topology orthogonal to the test
- * case.
- */
-
- private static class ExceptionMonitor implements ExceptionListener
- {
- List<JMSException> exceptions = new ArrayList<JMSException>();
-
- public void onException(JMSException e)
- {
- log.debug("ExceptionMonitor got JMSException: ", e);
-
- exceptions.add(e);
- }
-
- public boolean assertNoExceptions()
- {
- return exceptions.isEmpty();
- }
-
- public boolean assertOneJMSException()
- {
- return exceptions.size() == 1;
- }
-
- public boolean assertOneJMSExceptionWithLinkedCause(Class aClass)
- {
- if (exceptions.size() == 1)
- {
- JMSException e = exceptions.get(0);
-
- Exception linkedCause = e.getLinkedException();
-
- if ((linkedCause != null) && aClass.isInstance(linkedCause))
- {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Reports the number of exceptions held by this monitor.
- *
- * @return The number of exceptions held by this monitor.
- */
- public int size()
- {
- return exceptions.size();
- }
-
- public void reset()
- {
- exceptions = new ArrayList();
- }
-
- /**
- * Provides a dump of the stack traces of all exceptions that this exception monitor was notified of. Mainly
- * use for debugging/test failure reporting purposes.
- *
- * @return A string containing a dump of the stack traces of all exceptions.
- */
- public String toString()
- {
- String result = "ExceptionMonitor: holds " + exceptions.size() + " exceptions.\n\n";
-
- for (JMSException ex : exceptions)
- {
- result += getStackTrace(ex) + "\n";
- }
-
- return result;
- }
-
- /**
- * Prints an exception stack trace into a string.
- *
- * @param t The throwable to get the stack trace from.
- *
- * @return A string containing the throwables stack trace.
- */
- public static String getStackTrace(Throwable t)
- {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw, true);
- t.printStackTrace(pw);
- pw.flush();
- sw.flush();
-
- return sw.toString();
- }
- }
-
- public static class MessageMonitor implements MessageListener
- {
- public void onMessage(Message message)
- {
- log.debug("public void onMessage(Message message): called");
- }
- }
-
- /**
- * Establishes a JMS connection using a properties file and qpids built in JNDI implementation. This is a simple
- * convenience method for code that does anticipate handling connection failures. All exceptions that indicate
- * that the connection has failed, are wrapped as rutime exceptions, preumably handled by a top level failure
- * handler.
- *
- * @param messagingProps Any additional connection properties.
- *
- * @return A JMS conneciton.
- *
- * @todo Move this to a Utils library class or base test class. Also move the copy in interop.TestClient too.
- *
- * @todo Make in VM broker creation step optional on whether one is to be used or not.
- */
- public static Connection createConnection(ParsedProperties messagingProps)
- {
- log.debug("public static Connection createConnection(Properties messagingProps = " + messagingProps + "): called");
-
- try
- {
- // Extract the configured connection properties from the test configuration.
- String conUsername = messagingProps.getProperty(USERNAME_PROPNAME);
- String conPassword = messagingProps.getProperty(PASSWORD_PROPNAME);
- String virtualHost = messagingProps.getProperty(VIRTUAL_HOST_PROPNAME);
- String brokerUrl = messagingProps.getProperty(BROKER_PROPNAME);
-
- // Set up the broker connection url.
- String connectionString =
- "amqp://" + conUsername + ":" + conPassword + "/" + ((virtualHost != null) ? virtualHost : "")
- + "?brokerlist='" + brokerUrl + "'";
-
- // messagingProps.setProperty(CONNECTION_PROPNAME, connectionString);
-
- Context ctx = new InitialContext(messagingProps);
-
- ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CONNECTION_NAME);
- Connection connection = cf.createConnection();
-
- return connection;
- }
- catch (NamingException e)
- {
- log.debug("Got NamingException: ", e);
- throw new RuntimeException("Got JNDI NamingException whilst looking up the connection factory.", e);
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- throw new RuntimeException("Could not establish connection due to JMSException.", e);
- }
- }
-
- /**
- * Creates a publisher and a receiver on the same connection, configured according the to specified standard
- * properties.
- *
- * @param messagingProps The connection properties.
- *
- * @return A publisher/receiver client pair.
- */
- public static PublisherReceiver createPublisherReceiverPairSharedConnection(ParsedProperties messagingProps)
- {
- try
- {
- // Get a unique offset to append to destination names to make them unique to the connection.
- long uniqueId = uniqueDestsId.incrementAndGet();
-
- // Extract the standard test configuration parameters relevant to the connection.
- String destinationSendRoot = messagingProps.getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
- String destinationReceiveRoot =
- messagingProps.getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
- boolean createPublisherProducer = messagingProps.getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
- boolean createPublisherConsumer = messagingProps.getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
- boolean createReceiverProducer = messagingProps.getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
- boolean createReceiverConsumer = messagingProps.getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
-
- // Check which JMS flags and options are to be set.
- int ackMode = messagingProps.getPropertyAsInteger(ACK_MODE_PROPNAME);
- boolean useTopics = messagingProps.getPropertyAsBoolean(PUBSUB_PROPNAME);
- boolean transactional = messagingProps.getPropertyAsBoolean(TRANSACTED_PROPNAME);
- boolean durableSubscription = messagingProps.getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
-
- // Check if any Qpid/AMQP specific flags or options need to be set.
- boolean immediate = messagingProps.getPropertyAsBoolean(IMMEDIATE_PROPNAME);
- boolean mandatory = messagingProps.getPropertyAsBoolean(MANDATORY_PROPNAME);
- boolean needsQpidOptions = immediate | mandatory;
-
- /*log.debug("ackMode = " + ackMode);
- log.debug("useTopics = " + useTopics);
- log.debug("destinationSendRoot = " + destinationSendRoot);
- log.debug("destinationReceiveRoot = " + destinationReceiveRoot);
- log.debug("createPublisherProducer = " + createPublisherProducer);
- log.debug("createPublisherConsumer = " + createPublisherConsumer);
- log.debug("createReceiverProducer = " + createReceiverProducer);
- log.debug("createReceiverConsumer = " + createReceiverConsumer);
- log.debug("transactional = " + transactional);
- log.debug("immediate = " + immediate);
- log.debug("mandatory = " + mandatory);
- log.debug("needsQpidOptions = " + needsQpidOptions);*/
-
- // Create connection, sessions and producer/consumer pairs on each session.
- Connection connection = createConnection(messagingProps);
-
- // Add the connection exception listener to assert on exception conditions with.
- ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
- connection.setExceptionListener(exceptionMonitor);
-
- Session publisherSession = connection.createSession(transactional, ackMode);
- Session receiverSession = connection.createSession(transactional, ackMode);
-
- Destination publisherProducerDestination =
- useTopics ? (Destination) publisherSession.createTopic(destinationSendRoot)
- : publisherSession.createQueue(destinationSendRoot);
-
- MessageProducer publisherProducer =
- createPublisherProducer
- ? (needsQpidOptions
- ? ((AMQSession) publisherSession).createProducer(publisherProducerDestination, mandatory, immediate)
- : publisherSession.createProducer(publisherProducerDestination)) : null;
-
- MessageConsumer publisherConsumer =
- createPublisherConsumer
- ? publisherSession.createConsumer(publisherSession.createQueue(destinationReceiveRoot)) : null;
-
- if (publisherConsumer != null)
- {
- publisherConsumer.setMessageListener(new MessageMonitor());
- }
-
- MessageProducer receiverProducer =
- createReceiverProducer ? receiverSession.createProducer(receiverSession.createQueue(destinationReceiveRoot))
- : null;
-
- Destination receiverConsumerDestination =
- useTopics ? (Destination) receiverSession.createTopic(destinationSendRoot)
- : receiverSession.createQueue(destinationSendRoot);
-
- MessageConsumer receiverConsumer =
- createReceiverConsumer
- ? ((durableSubscription && useTopics)
- ? receiverSession.createDurableSubscriber((Topic) receiverConsumerDestination, "testsub")
- : receiverSession.createConsumer(receiverConsumerDestination)) : null;
-
- if (receiverConsumer != null)
- {
- receiverConsumer.setMessageListener(new MessageMonitor());
- }
-
- // Start listening for incoming messages.
- connection.start();
-
- // Package everything up.
- ProducerConsumerPair publisher =
- new ProducerConsumerPairImpl(publisherProducer, publisherConsumer, publisherSession);
- ProducerConsumerPair receiver =
- new ProducerConsumerPairImpl(receiverProducer, receiverConsumer, receiverSession);
-
- PublisherReceiver result = new PublisherReceiverImpl(publisher, receiver, connection, exceptionMonitor);
-
- return result;
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- throw new RuntimeException("Could not create publisher/receiver pair due to a JMSException.", e);
- }
- }
-
- public static Message createTestMessage(ProducerConsumerPair client, ParsedProperties testProps) throws JMSException
- {
- return client.getSession().createTextMessage("Hello");
- // return client.getSession().createMessage();
- }
-
- /**
- * A ProducerConsumerPair is a pair consisting of one message producer and one message consumer. It is a standard
- * unit of connectivity allowing a full-duplex conversation to be held, provided both the consumer and producer
- * are instantiated and configured.
- *
- * In some situations a test, or piece of application code will be written with differing numbers of publishers
- * and receivers in different roles, where one role produces only and one consumes only. This messaging topology
- * can still make use of producer/consumer pairs as standard building blocks, combined into publisher/receiver
- * units to fulfill the different messaging roles, with the publishers consumer uninstantiated and the receivers
- * producer uninstantiated. Use a {@link PublisherReceiver} for this.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Provide a message producer for sending messages.
- * <tr><td> Provide a message consumer for receiving messages.
- * </table>
- *
- * @todo Update the {@link org.apache.qpid.util.ConversationFactory} so that it accepts these as the basic
- * conversation connection units.
- */
- public static interface ProducerConsumerPair
- {
- public MessageProducer getProducer();
-
- public MessageConsumer getConsumer();
-
- public void send(Message message) throws JMSException;
-
- public Session getSession();
-
- public void close() throws JMSException;
- }
-
- /**
- * A single producer and consumer.
- */
- public static class ProducerConsumerPairImpl implements ProducerConsumerPair
- {
- MessageProducer producer;
-
- MessageConsumer consumer;
-
- Session session;
-
- public ProducerConsumerPairImpl(MessageProducer producer, MessageConsumer consumer, Session session)
- {
- this.producer = producer;
- this.consumer = consumer;
- this.session = session;
- }
-
- public MessageProducer getProducer()
- {
- return producer;
- }
-
- public MessageConsumer getConsumer()
- {
- return consumer;
- }
-
- public void send(Message message) throws JMSException
- {
- producer.send(message);
- }
-
- public Session getSession()
- {
- return session;
- }
-
- public void close() throws JMSException
- {
- if (producer != null)
- {
- producer.close();
- }
-
- if (consumer != null)
- {
- consumer.close();
- }
- }
- }
-
- /**
- * Multiple producers and consumers made to look like a single producer and consumer. All methods repeated accross
- * all producers and consumers.
- */
- public static class MultiProducerConsumerPairImpl implements ProducerConsumerPair
- {
- public MessageProducer getProducer()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public MessageConsumer getConsumer()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public void send(Message message) throws JMSException
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public Session getSession()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public void close()
- {
- throw new RuntimeException("Not implemented.");
- }
- }
-
- /**
- * A PublisherReceiver consists of two sets of producer/consumer pairs, one for an 'instigating' publisher
- * role, and one for a more 'passive' receiver role.
- *
- * <p/>A set of publishers and receivers forms a typical test configuration where both roles are to be controlled
- * from within a single JVM. This is not a particularly usefull arrangement for applications which want to place
- * these roles on physically seperate machines and pass messages between them. It is a faily normal arrangement for
- * test code though, either to publish and receive messages through an in-VM message broker in order to test its
- * expected behaviour, or to publish and receive (possibly bounced back) messages through a seperate broker instance
- * in order to take performance timings. In the case of performance timings, the co-location of the publisher and
- * receiver means that the timings are taken on the same machine for accurate timing without the need for clock
- * synchronization.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Manage an m*n array of publisher and recievers.
- * </table>
- */
- public static interface PublisherReceiver
- {
- public ProducerConsumerPair getPublisher();
-
- public ProducerConsumerPair getReceiver();
-
- public void start();
-
- public void send(ParsedProperties testProps, int numMessages);
-
- public ExceptionMonitor getConnectionExceptionMonitor();
-
- public ExceptionMonitor getExceptionMonitor();
-
- public void testWithAssertions(ParsedProperties testProps, Class aClass /*, assertions */);
-
- public void testNoExceptions(ParsedProperties testProps);
-
- public void close();
- }
-
- public static class PublisherReceiverImpl implements PublisherReceiver
- {
- private ProducerConsumerPair publisher;
- private ProducerConsumerPair receiver;
- private Connection connection;
- private ExceptionMonitor connectionExceptionMonitor;
- private ExceptionMonitor exceptionMonitor;
-
- public PublisherReceiverImpl(ProducerConsumerPair publisher, ProducerConsumerPair receiver, Connection connection,
- ExceptionMonitor connectionExceptionMonitor)
- {
- this.publisher = publisher;
- this.receiver = receiver;
- this.connection = connection;
- this.connectionExceptionMonitor = connectionExceptionMonitor;
- this.exceptionMonitor = new ExceptionMonitor();
- }
-
- public ProducerConsumerPair getPublisher()
- {
- return publisher;
- }
-
- public ProducerConsumerPair getReceiver()
- {
- return receiver;
- }
-
- public void start()
- { }
-
- public void close()
- {
- try
- {
- publisher.close();
- receiver.close();
- connection.close();
- }
- catch (JMSException e)
- {
- throw new RuntimeException("Got JMSException during close.", e);
- }
- }
-
- public ExceptionMonitor getConnectionExceptionMonitor()
- {
- return connectionExceptionMonitor;
- }
-
- public ExceptionMonitor getExceptionMonitor()
- {
- return exceptionMonitor;
- }
-
- public void send(ParsedProperties testProps, int numMessages)
- {
- boolean transactional = testProps.getPropertyAsBoolean(TRANSACTED_PROPNAME);
-
- // Send an immediate message through the publisher and ensure that it results in a JMSException.
- try
- {
- getPublisher().send(createTestMessage(getPublisher(), testProps));
-
- if (transactional)
- {
- getPublisher().getSession().commit();
- }
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- exceptionMonitor.onException(e);
- }
- }
-
- public void testWithAssertions(ParsedProperties testProps, Class aClass /*, assertions */)
- {
- start();
- send(testProps, 1);
- pause(1000L);
-
- String errors = "";
-
- ExceptionMonitor connectionExceptionMonitor = getConnectionExceptionMonitor();
- if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(aClass))
- {
- errors += "Was expecting linked exception type " + aClass.getName() + " on the connection.\n";
- errors +=
- (connectionExceptionMonitor.size() > 0)
- ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
- : "Got no exceptions on the connection.";
- }
-
- // Clean up the publisher/receiver client pair.
- close();
-
- assertEquals(errors, "", errors);
- }
-
- /**
- */
- public void testNoExceptions(ParsedProperties testProps)
- {
- start();
- send(testProps, 1);
- pause(1000L);
-
- String errors = "";
-
- if (!getConnectionExceptionMonitor().assertNoExceptions())
- {
- errors += "Was expecting no exceptions.\n";
- errors += "Got the following exceptions on the connection, " + getConnectionExceptionMonitor();
- }
-
- if (!getExceptionMonitor().assertNoExceptions())
- {
- errors += "Was expecting no exceptions.\n";
- errors += "Got the following exceptions on the producer, " + getExceptionMonitor();
- }
-
- // Clean up the publisher/receiver client pair.
- close();
-
- assertEquals(errors, "", errors);
- }
-
- public static PublisherReceiver connectClients(ParsedProperties testProps)
- {
- // Create a standard publisher/receiver test client pair on a shared connection, individual sessions.
- return createPublisherReceiverPairSharedConnection(testProps);
- }
- }
-
- /**
- * Pauses for the specified length of time. In the event of failing to pause for at least that length of time
- * due to interuption of the thread, a RutimeException is raised to indicate the failure. The interupted status
- * of the thread is restores in that case. This method should only be used when it is expected that the pause
- * will be succesfull, for example in test code that relies on inejecting a pause.
- *
- * @param t The minimum time to pause for in milliseconds.
- */
- public static void pause(long t)
- {
- try
- {
- Thread.sleep(t);
- }
- catch (InterruptedException e)
- {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
-
- throw new RuntimeException("Failed to generate the requested pause length.", e);
- }
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java
index 0bc31befe8..75257cc508 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java
@@ -20,17 +20,11 @@
*/
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
-
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQNoRouteException;
-import org.apache.qpid.client.transport.TransportConnection;
-import static org.apache.qpid.server.exchange.MessagingTestConfigProperties.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.CircuitImpl;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
@@ -54,41 +48,39 @@ import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
* <tr><dt> Check that a mandatory message is send successfully, in a transactions, when a consumer is
* disconnected but when the route exists.
* </table>
+ *
+ * @todo All of these test cases will be generated by a test generator that thoroughly tests all combinations of test
+ * circuits.
*/
-public class MandatoryMessageTest extends TestCase
+public class MandatoryMessageTest extends FrameworkBaseCase
{
- /** Used for debugging. */
- private static final Logger log = LoggerFactory.getLogger(MandatoryMessageTest.class);
-
/** Used to read the tests configurable properties through. */
ParsedProperties testProps;
/** Check that an mandatory message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_508_MandatoryOkNoTxP2P() throws Exception
+ public void test_QPID_508_MandatoryOkNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an mandatory message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_508_MandatoryOkTxP2P() throws Exception
+ public void test_QPID_508_MandatoryOkTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
@@ -101,14 +93,13 @@ public class MandatoryMessageTest extends TestCase
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
@@ -121,18 +112,17 @@ public class MandatoryMessageTest extends TestCase
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an mandatory message results in no route code, not using transactions, when no consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteNoTxP2P() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -142,15 +132,14 @@ public class MandatoryMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an mandatory message results in no route code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteTxP2P() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -160,39 +149,36 @@ public class MandatoryMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an mandatory message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_508_MandatoryOkNoTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryOkNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an mandatory message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_508_MandatoryOkTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryOkTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
@@ -208,14 +194,13 @@ public class MandatoryMessageTest extends TestCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
@@ -231,18 +216,17 @@ public class MandatoryMessageTest extends TestCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/** Check that an mandatory message results in no route code, not using transactions, when no consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteNoTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -252,15 +236,14 @@ public class MandatoryMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an mandatory message results in no route code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -270,16 +253,15 @@ public class MandatoryMessageTest extends TestCase
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ Circuit testCircuit = CircuitImpl.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
protected void setUp() throws Exception
{
- NDC.push(getName());
+ super.setUp();
testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
@@ -289,22 +271,5 @@ public class MandatoryMessageTest extends TestCase
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
-
- // Ensure that the in-vm broker is created.
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- try
- {
- // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
- TransportConnection.killVMBroker(1);
- ApplicationRegistry.remove(1);
- }
- finally
- {
- NDC.pop();
- }
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java
new file mode 100644
index 0000000000..75c1c97999
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.test.framework;
+
+/**
+ * Assertion models an assertion on a test {@link Circuit}.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Indicate whether or not the assertion passes when applied.
+ * </table>
+ */
+public interface Assertion
+{
+ /**
+ * Applies the assertion.
+ *
+ * @return <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails.
+ */
+ public boolean apply();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java
new file mode 100644
index 0000000000..e939b66c31
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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.test.framework;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * AssertionBase is a base class for implenmenting assertions. It provides a mechanism to store error messages, and
+ * report all error messages when its {@link #toString()} method is called.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public abstract class AssertionBase implements Assertion
+{
+ /** Holds the error messages. */
+ List<String> errors = new LinkedList<String>();
+
+ /**
+ * Adds an error message to the assertion.
+ *
+ * @param error An error message to add to the assertion.
+ */
+ public void addError(String error)
+ {
+ errors.add(error);
+ }
+
+ /**
+ * Prints all of the error messages in the assertion into a string.
+ *
+ * @return All of the error messages in the assertion as a string.
+ */
+ public String toString()
+ {
+ String result = "";
+
+ for (String error : errors)
+ {
+ result += error;
+ }
+
+ return result;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java
new file mode 100644
index 0000000000..83a6d7279b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java
@@ -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.test.framework;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import java.util.List;
+
+/**
+ * A Circuit is the basic test unit against which test cases are to be written. A circuit consists of two 'ends', an
+ * instigating 'publisher' end and a more passive 'receiver' end.
+ *
+ * <p/>Once created, the life-cycle of a circuit may be controlled by {@link #start()}ing it, or {@link #close()}ing it.
+ * Once started, the circuit is ready to send messages over. Once closed the circuit can no longer be used.
+ *
+ * <p/>The state of the circuit may be taken with the {@link #check()} method, and asserted against by the
+ * {@link #applyAssertions(java.util.List)} method.
+ *
+ * <p/>There is a default test procedure which may be performed against the circuit. The outline of this procedure is:
+ *
+ * <p/><pre>
+ * Start the circuit.
+ * Send test messages.
+ * Request a status report.
+ * Assert conditions on the publishing end of the circuit.
+ * Assert conditions on the receiving end of the circuit.
+ * Close the circuit.
+ * Pass with no failed assertions or fail with a list of failed assertions.
+ * </pre>
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ * <tr><td> Start the circuit running.
+ * <tr><td> Close the circuit down.
+ * <tr><td> Take a reading of the circuits state.
+ * <tr><td> Apply assertions against the circuits state.
+ * <tr><td> Send test messages over the circuit.
+ * <tr><td> Perform the default test procedue on the circuit.
+ * </table>
+ */
+public interface Circuit
+{
+ /**
+ * Gets the interface on the publishing end of the circuit.
+ *
+ * @return The publishing end of the circuit.
+ */
+ public Publisher getPublisher();
+
+ /**
+ * Gets the interface on the receiving end of the circuit.
+ *
+ * @return The receiving end of the circuit.
+ */
+ public Receiver getReceiver();
+
+ /**
+ * Connects and starts the circuit. After this method is called the circuit is ready to send messages.
+ */
+ public void start();
+
+ /**
+ * Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ * into a report, against which assertions may be checked.
+ */
+ public void check();
+
+ /**
+ * Closes the circuit. All associated resources are closed.
+ */
+ public void close();
+
+ /**
+ * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * this, to ensure that the circuit has gathered its state into a report to assert against.
+ *
+ * @param assertions The list of assertions to apply.
+ *
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> applyAssertions(List<Assertion> assertions);
+
+ /**
+ * Sends a message on the test circuit. The exact nature of the message sent is controlled by the test parameters.
+ */
+ public void send();
+
+ /**
+ * Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
+ *
+ * @param numMessages The number of messages to send using the default test procedure.
+ * @param assertions The list of assertions to apply.
+ *
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> test(int numMessages, List<Assertion> assertions);
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java
new file mode 100644
index 0000000000..43c3fa4c66
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.*;
+
+/**
+ * A CircuitEnd is a pair consisting of one message producer and one message consumer, that represents one end of a
+ * test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
+ * the consumer and producer are instantiated and configured.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * </table>
+ *
+ * @todo Update the {@link org.apache.qpid.util.ConversationFactory} so that it accepts these as the basic conversation
+ * connection units.
+ */
+public interface CircuitEnd
+{
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer();
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer();
+
+ /**
+ * Send the specified message over the producer at this end point.
+ *
+ * @param message The message to send.
+ *
+ * @throws JMSException Any JMS exception occuring during the send is allowed to fall through.
+ */
+ public void send(Message message) throws JMSException;
+
+ /**
+ * Gets the JMS Session associated with this circuit end point.
+ *
+ * @return The JMS Session associated with this circuit end point.
+ */
+ public Session getSession();
+
+ /**
+ * Closes the message producers and consumers and the sessions, associated with this circuit end point.
+ *
+ * @throws JMSException Any JMSExceptions occurring during the close are allowed to fall through.
+ */
+ public void close() throws JMSException;
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java
new file mode 100644
index 0000000000..54a30d9c6e
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java
@@ -0,0 +1,119 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.*;
+
+/**
+ * A CircuitEndBase is a pair consisting of one message producer and one message consumer, that represents one end of a
+ * test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
+ * the consumer and producer are instantiated and configured.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * </table>
+ */
+public class CircuitEndBase implements CircuitEnd
+{
+ /** Holds the single message producer. */
+ MessageProducer producer;
+
+ /** Holds the single message consumer. */
+ MessageConsumer consumer;
+
+ /** Holds the session for the circuit end. */
+ Session session;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public CircuitEndBase(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ this.producer = producer;
+ this.consumer = consumer;
+ this.session = session;
+ }
+
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer()
+ {
+ return producer;
+ }
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer()
+ {
+ return consumer;
+ }
+
+ /**
+ * Send the specified message over the producer at this end point.
+ *
+ * @param message The message to send.
+ * @throws javax.jms.JMSException Any JMS exception occuring during the send is allowed to fall through.
+ */
+ public void send(Message message) throws JMSException
+ {
+ producer.send(message);
+ }
+
+ /**
+ * Gets the JMS Session associated with this circuit end point.
+ *
+ * @return The JMS Session associated with this circuit end point.
+ */
+ public Session getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Closes the message producers and consumers and the sessions, associated with this circuit end point.
+ *
+ * @throws javax.jms.JMSException Any JMSExceptions occurring during the close are allowed to fall through.
+ */
+ public void close() throws JMSException
+ {
+ if (producer != null)
+ {
+ producer.close();
+ }
+
+ if (consumer != null)
+ {
+ consumer.close();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitImpl.java
new file mode 100644
index 0000000000..936ac57a4b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitImpl.java
@@ -0,0 +1,384 @@
+/*
+ *
+ * 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.test.framework;
+
+import junit.framework.Assert;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.framework.MessageMonitor;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.*;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ * <tr><td> Start the circuit running.
+ * <tr><td> Close the circuit down.
+ * <tr><td> Take a reading of the circuits state.
+ * <tr><td> Apply assertions against the circuits state.
+ * <tr><td> Send test messages over the circuit.
+ * <tr><td> Perform the default test procedue on the circuit.
+ * </table>
+ */
+public class CircuitImpl implements Circuit
+{
+ /** Used to create unique destination names for each test. */
+ private static AtomicLong uniqueDestsId = new AtomicLong();
+
+ /** Holds the test configuration for the circuit. */
+ private ParsedProperties testProps;
+
+ /** Holds the publishing end of the circuit. */
+ private PublisherImpl publisher;
+
+ /** Holds the receiving end of the circuit. */
+ private ReceiverImpl receiver;
+
+ /** Holds the connection for the publishing end of the circuit. */
+ private Connection connection;
+
+ /** Holds the exception listener for the connection on the publishing end of the circuit. */
+ private ExceptionMonitor connectionExceptionMonitor;
+
+ /** Holds the exception listener for the session on the publishing end of the circuit. */
+ private ExceptionMonitor exceptionMonitor;
+
+ /**
+ * Creates a test circuit using the specified test parameters. The publisher, receiver, connection and
+ * connection monitor must already have been created, to assemble the circuit.
+ *
+ * @param testProps The test parameters.
+ * @param publisher The test publisher.
+ * @param receiver The test receiver.
+ * @param connection The connection.
+ * @param connectionExceptionMonitor The connection exception monitor.
+ */
+ protected CircuitImpl(ParsedProperties testProps, PublisherImpl publisher, ReceiverImpl receiver, Connection connection,
+ ExceptionMonitor connectionExceptionMonitor)
+ {
+ this.testProps = testProps;
+ this.publisher = publisher;
+ this.receiver = receiver;
+ this.connection = connection;
+ this.connectionExceptionMonitor = connectionExceptionMonitor;
+ this.exceptionMonitor = new ExceptionMonitor();
+
+ // Set this as the parent circuit on the publisher and receiver.
+ publisher.setCircuit(this);
+ receiver.setCircuit(this);
+ }
+
+ /**
+ * Creates a test circuit from the specified test parameters.
+ *
+ * @param testProps The test parameters.
+ *
+ * @return A connected and ready to start, test circuit.
+ */
+ public static Circuit createCircuit(ParsedProperties testProps)
+ {
+ // Create a standard publisher/receiver test client pair on a shared connection, individual sessions.
+ try
+ {
+ // Get a unique offset to append to destination names to make them unique to the connection.
+ long uniqueId = uniqueDestsId.incrementAndGet();
+
+ // Extract the standard test configuration parameters relevant to the connection.
+ String destinationSendRoot =
+ testProps.getProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
+ String destinationReceiveRoot =
+ testProps.getProperty(MessagingTestConfigProperties.RECEIVE_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
+ boolean createPublisherProducer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBLISHER_PRODUCER_BIND_PROPNAME);
+ boolean createPublisherConsumer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBLISHER_CONSUMER_BIND_PROPNAME);
+ boolean createReceiverProducer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.RECEIVER_PRODUCER_BIND_PROPNAME);
+ boolean createReceiverConsumer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.RECEIVER_CONSUMER_BIND_PROPNAME);
+
+ // Check which JMS flags and options are to be set.
+ int ackMode = testProps.getPropertyAsInteger(MessagingTestConfigProperties.ACK_MODE_PROPNAME);
+ boolean useTopics = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBSUB_PROPNAME);
+ boolean transactional = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.TRANSACTED_PROPNAME);
+ boolean durableSubscription =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.DURABLE_SUBSCRIPTION_PROPNAME);
+
+ // Check if any Qpid/AMQP specific flags or options need to be set.
+ boolean immediate = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.IMMEDIATE_PROPNAME);
+ boolean mandatory = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.MANDATORY_PROPNAME);
+ boolean needsQpidOptions = immediate | mandatory;
+
+ /*log.debug("ackMode = " + ackMode);
+ log.debug("useTopics = " + useTopics);
+ log.debug("destinationSendRoot = " + destinationSendRoot);
+ log.debug("destinationReceiveRoot = " + destinationReceiveRoot);
+ log.debug("createPublisherProducer = " + createPublisherProducer);
+ log.debug("createPublisherConsumer = " + createPublisherConsumer);
+ log.debug("createReceiverProducer = " + createReceiverProducer);
+ log.debug("createReceiverConsumer = " + createReceiverConsumer);
+ log.debug("transactional = " + transactional);
+ log.debug("immediate = " + immediate);
+ log.debug("mandatory = " + mandatory);
+ log.debug("needsQpidOptions = " + needsQpidOptions);*/
+
+ // Create connection, sessions and producer/consumer pairs on each session.
+ Connection connection = TestUtils.createConnection(testProps);
+
+ // Add the connection exception listener to assert on exception conditions with.
+ ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
+ connection.setExceptionListener(exceptionMonitor);
+
+ Session publisherSession = connection.createSession(transactional, ackMode);
+ Session receiverSession = connection.createSession(transactional, ackMode);
+
+ Destination publisherProducerDestination =
+ useTopics ? publisherSession.createTopic(destinationSendRoot)
+ : publisherSession.createQueue(destinationSendRoot);
+
+ MessageProducer publisherProducer =
+ createPublisherProducer
+ ? (needsQpidOptions
+ ? ((AMQSession) publisherSession).createProducer(publisherProducerDestination, mandatory, immediate)
+ : publisherSession.createProducer(publisherProducerDestination)) : null;
+
+ MessageConsumer publisherConsumer =
+ createPublisherConsumer
+ ? publisherSession.createConsumer(publisherSession.createQueue(destinationReceiveRoot)) : null;
+
+ if (publisherConsumer != null)
+ {
+ publisherConsumer.setMessageListener(new MessageMonitor());
+ }
+
+ MessageProducer receiverProducer =
+ createReceiverProducer ? receiverSession.createProducer(receiverSession.createQueue(destinationReceiveRoot))
+ : null;
+
+ Destination receiverConsumerDestination =
+ useTopics ? receiverSession.createTopic(destinationSendRoot)
+ : receiverSession.createQueue(destinationSendRoot);
+
+ MessageConsumer receiverConsumer =
+ createReceiverConsumer
+ ? ((durableSubscription && useTopics)
+ ? receiverSession.createDurableSubscriber((Topic) receiverConsumerDestination, "testsub")
+ : receiverSession.createConsumer(receiverConsumerDestination)) : null;
+
+ if (receiverConsumer != null)
+ {
+ receiverConsumer.setMessageListener(new MessageMonitor());
+ }
+
+ // Start listening for incoming messages.
+ connection.start();
+
+ // Package everything up.
+ PublisherImpl publisher = new PublisherImpl(publisherProducer, publisherConsumer, publisherSession);
+ ReceiverImpl receiver = new ReceiverImpl(receiverProducer, receiverConsumer, receiverSession);
+
+ return new CircuitImpl(testProps, publisher, receiver, connection, exceptionMonitor);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Could not create publisher/receiver pair due to a JMSException.", e);
+ }
+ }
+
+ /**
+ * Gets the interface on the publishing end of the circuit.
+ *
+ * @return The publishing end of the circuit.
+ */
+ public Publisher getPublisher()
+ {
+ return publisher;
+ }
+
+ /**
+ * Gets the interface on the receiving end of the circuit.
+ *
+ * @return The receiving end of the circuit.
+ */
+ public Receiver getReceiver()
+ {
+ return receiver;
+ }
+
+ /**
+ * Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ * into a report, against which assertions may be checked.
+ */
+ public void check()
+ { }
+
+ /**
+ * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * this, to ensure that the circuit has gathered its state into a report to assert against.
+ *
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> applyAssertions(List<Assertion> assertions)
+ {
+ return null;
+ }
+
+ /**
+ * Connects and starts the circuit. After this method is called the circuit is ready to send messages.
+ */
+ public void start()
+ { }
+
+ /**
+ * Closes the circuit. All associated resources are closed.
+ */
+ public void close()
+ {
+ try
+ {
+ publisher.close();
+ receiver.close();
+ connection.close();
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Got JMSException during close.", e);
+ }
+ }
+
+ /**
+ * Sends a message on the test circuit. The exact nature of the message sent is controlled by the test parameters.
+ */
+ public void send()
+ {
+ boolean transactional = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.TRANSACTED_PROPNAME);
+
+ // Send an immediate message through the publisher and ensure that it results in a JMSException.
+ try
+ {
+ getPublisher().send(createTestMessage(getPublisher()));
+
+ if (transactional)
+ {
+ getPublisher().getSession().commit();
+ }
+ }
+ catch (JMSException e)
+ {
+ exceptionMonitor.onException(e);
+ }
+ }
+
+ /**
+ * Runs the default test procedure against the circuit, and checks that all of the specified assertions hold. The
+ * outline of the default test procedure is:
+ *
+ * <p/><pre>
+ * Start the circuit.
+ * Send test messages.
+ * Request a status report.
+ * Assert conditions on the publishing end of the circuit.
+ * Assert conditions on the receiving end of the circuit.
+ * Close the circuit.
+ * Pass with no failed assertions or fail with a list of failed assertions.
+ * </pre>
+ *
+ * @param numMessages The number of messages to send using the default test procedure.
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> test(int numMessages, List<Assertion> assertions)
+ {
+ // Start the test circuit.
+ start();
+
+ // Send the requested number of test messages.
+ for (int i = 0; i < numMessages; i++)
+ {
+ send();
+ }
+
+ // Inject a short pause to allow time for exceptions to come back asynchronously.
+ TestUtils.pause(100L);
+
+ // Request a status report.
+ check();
+
+ // Apply all of the requested assertions, keeping record of any that fail.
+ List<Assertion> failures = new LinkedList<Assertion>();
+
+ for (Assertion assertion : assertions)
+ {
+ if (!assertion.apply())
+ {
+ failures.add(assertion);
+ }
+ }
+
+ // Clean up the publisher/receiver/session/connections.
+ close();
+
+ // Return any failed assertions to the caller.
+ return failures;
+ }
+
+ /**
+ * Creates a message with the properties defined as per the test parameters.
+ *
+ * @param client The circuit end to create the message on.
+ *
+ * @return The test message.
+ *
+ * @throws JMSException Any JMSException occurring during creation of the message is allowed to fall through.
+ */
+ private Message createTestMessage(CircuitEnd client) throws JMSException
+ {
+ return client.getSession().createTextMessage("Hello");
+ }
+
+ /**
+ * Gets the exception monitor for the publishing ends connection.
+ *
+ * @return The exception monitor for the publishing ends connection.
+ */
+ public ExceptionMonitor getConnectionExceptionMonitor()
+ {
+ return connectionExceptionMonitor;
+ }
+
+ /**
+ * Gets the exception monitor for the publishing ends session.
+ *
+ * @return The exception monitor for the publishing ends session.
+ */
+ public ExceptionMonitor getExceptionMonitor()
+ {
+ return exceptionMonitor;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java b/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java
new file mode 100644
index 0000000000..9f4e8b2142
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+* <tr><th> Responsibilities <th> Collaborations
+* <tr><td>
+* </table>
+*/
+public class ExceptionMonitor implements ExceptionListener
+{
+ List<JMSException> exceptions = new ArrayList<JMSException>();
+
+ public void onException(JMSException e)
+ {
+ exceptions.add(e);
+ }
+
+ public boolean assertNoExceptions()
+ {
+ return exceptions.isEmpty();
+ }
+
+ public boolean assertOneJMSException()
+ {
+ return exceptions.size() == 1;
+ }
+
+ public boolean assertOneJMSExceptionWithLinkedCause(Class aClass)
+ {
+ if (exceptions.size() == 1)
+ {
+ JMSException e = exceptions.get(0);
+
+ Exception linkedCause = e.getLinkedException();
+
+ if ((linkedCause != null) && aClass.isInstance(linkedCause))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Reports the number of exceptions held by this monitor.
+ *
+ * @return The number of exceptions held by this monitor.
+ */
+ public int size()
+ {
+ return exceptions.size();
+ }
+
+ public void reset()
+ {
+ exceptions = new ArrayList();
+ }
+
+ /**
+ * Provides a dump of the stack traces of all exceptions that this exception monitor was notified of. Mainly
+ * use for debugging/test failure reporting purposes.
+ *
+ * @return A string containing a dump of the stack traces of all exceptions.
+ */
+ public String toString()
+ {
+ String result = "ExceptionMonitor: holds " + exceptions.size() + " exceptions.\n\n";
+
+ for (JMSException ex : exceptions)
+ {
+ result += getStackTrace(ex) + "\n";
+ }
+
+ return result;
+ }
+
+ /**
+ * Prints an exception stack trace into a string.
+ *
+ * @param t The throwable to get the stack trace from.
+ *
+ * @return A string containing the throwables stack trace.
+ */
+ public static String getStackTrace(Throwable t)
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ t.printStackTrace(pw);
+ pw.flush();
+ sw.flush();
+
+ return sw.toString();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java
new file mode 100644
index 0000000000..9ce44305ad
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * 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.test.framework;
+
+import junit.framework.TestCase;
+
+import org.apache.log4j.NDC;
+
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * FrameworkBaseCase provides a starting point for writing test cases against the test framework. Its main purpose is
+ * to provide some convenience methods for testing.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Create and clean up in-vm brokers on every test case.
+ * <tr><td> Produce lists of assertions from assertion creation calls.
+ * <tr><td> Produce JUnit failures from assertion failures.
+ * <tr><td> Convert failed assertions to error messages.
+ * </table>
+ */
+public class FrameworkBaseCase extends TestCase
+{
+ /**
+ * Creates a list of assertions.
+ *
+ * @param asserts The assertions to compile in a list.
+ *
+ * @return A list of assertions.
+ */
+ protected List<Assertion> assertionList(Assertion... asserts)
+ {
+ List<Assertion> result = new ArrayList<Assertion>();
+
+ for (Assertion assertion : asserts)
+ {
+ result.add(assertion);
+ }
+
+ return result;
+ }
+
+ /**
+ * Generates a JUnit assertion exception (failure) if any assertions are passed into this method, also concatenating
+ * all of the error messages in the assertions together to form an error message to diagnose the test failure with.
+ *
+ * @param asserts The list of failed assertions.
+ */
+ protected void assertNoFailures(List<Assertion> asserts)
+ {
+ // Check if there are no assertion failures, and return without doing anything if so.
+ if ((asserts == null) || asserts.isEmpty())
+ {
+ return;
+ }
+
+ // Compile all of the assertion failure messages together.
+ String errorMessage = assertionsToString(asserts);
+
+ // Fail with the error message from all of the assertions.
+ fail(errorMessage);
+ }
+
+ /**
+ * Converts a list of failed assertions into an error message.
+ *
+ * @param asserts The failed assertions.
+ *
+ * @return The error message.
+ */
+ protected String assertionsToString(List<Assertion> asserts)
+ {
+ String errorMessage = "";
+
+ for (Assertion assertion : asserts)
+ {
+ errorMessage += assertion.toString() + "\n";
+ }
+
+ return errorMessage;
+ }
+
+ /**
+ * Ensures that the in-vm broker is created and initialized.
+ *
+ * @throws Exception Any exceptions allowed to fall through and fail the test.
+ */
+ protected void setUp() throws Exception
+ {
+ NDC.push(getName());
+
+ // Ensure that the in-vm broker is created.
+ TransportConnection.createVMBroker(1);
+ }
+
+ /**
+ * Ensures that the in-vm broker is cleaned up after each test run.
+ */
+ protected void tearDown()
+ {
+ try
+ {
+ // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
+ TransportConnection.killVMBroker(1);
+ ApplicationRegistry.remove(1);
+ }
+ finally
+ {
+ NDC.pop();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java
new file mode 100644
index 0000000000..63ff99826b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class MessageMonitor implements MessageListener
+{
+ public void onMessage(Message message)
+ { }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java
index b584c8c80b..62229f3c72 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java
@@ -18,7 +18,7 @@
* under the License.
*
*/
-package org.apache.qpid.server.exchange;
+package org.apache.qpid.test.framework;
import org.apache.qpid.jms.Session;
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/MultiProducerConsumerPairImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MultiProducerConsumerPairImpl.java
new file mode 100644
index 0000000000..55bf141f93
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MultiProducerConsumerPairImpl.java
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.*;
+
+/**
+ * Multiple producers and consumers made to look like a single producer and consumer. All methods repeated accross
+ * all producers and consumers.
+ */
+public class MultiProducerConsumerPairImpl implements CircuitEnd
+{
+
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Send the specified message over the producer at this end point.
+ *
+ * @param message The message to send.
+ * @throws javax.jms.JMSException Any JMS exception occuring during the send is allowed to fall through.
+ */
+ public void send(Message message) throws JMSException
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Gets the JMS Session associated with this circuit end point.
+ *
+ * @return The JMS Session associated with this circuit end point.
+ */
+ public Session getSession()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Closes the message producers and consumers and the sessions, associated with this circuit end point.
+ *
+ * @throws javax.jms.JMSException Any JMSExceptions occurring during the close are allowed to fall through.
+ */
+ public void close() throws JMSException
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java
new file mode 100644
index 0000000000..eed2edfb5e
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.test.framework;
+
+/**
+ * A Publisher is a {@link CircuitEnd} that represents one end of a test circuit. Its main purpose is to
+ * provide assertions that can be applied to test the behaviour of the publisher.
+ */
+public interface Publisher extends CircuitEnd
+{
+ /**
+ * Provides an assertion that the publisher encountered no exceptions.
+ *
+ * @return An assertion that the publisher encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion();
+
+ /**
+ * Provides an assertion that the publisher got a no consumers exception on every message.
+ *
+ * @return An assertion that the publisher got a no consumers exception on every message.
+ */
+ public Assertion noConsumersAssertion();
+
+ /**
+ * Provides an assertion that the publisher got a no rout exception on every message.
+ *
+ * @return An assertion that the publisher got a no rout exception on every message.
+ */
+ public Assertion noRouteAssertion();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/PublisherImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/PublisherImpl.java
new file mode 100644
index 0000000000..46427ce89f
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/PublisherImpl.java
@@ -0,0 +1,153 @@
+/*
+ *
+ * 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.test.framework;
+
+import org.apache.qpid.client.AMQNoConsumersException;
+import org.apache.qpid.client.AMQNoRouteException;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class PublisherImpl extends CircuitEndBase implements Publisher
+{
+ /** Holds a reference to the containing circuit. */
+ private CircuitImpl circuit;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public PublisherImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ super(producer, consumer, session);
+ }
+
+ /**
+ * Provides an assertion that the publisher encountered no exceptions.
+ *
+ * @return An assertion that the publisher encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor sessionExceptionMonitor = circuit.getExceptionMonitor();
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertNoExceptions())
+ {
+ passed = false;
+ addError("Was expecting no exceptions.\n");
+ addError("Got the following exceptions on the connection, "
+ + circuit.getConnectionExceptionMonitor());
+ }
+
+ if (!sessionExceptionMonitor.assertNoExceptions())
+ {
+ passed = false;
+ addError("Was expecting no exceptions.\n");
+ addError("Got the following exceptions on the producer, " + circuit.getExceptionMonitor());
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Provides an assertion that the publisher got a no consumers exception on every message.
+ *
+ * @return An assertion that the publisher got a no consumers exception on every message.
+ */
+ public Assertion noConsumersAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoConsumersException.class))
+ {
+ addError("Was expecting linked exception type " + AMQNoConsumersException.class.getName()
+ + " on the connection.\n");
+ addError((connectionExceptionMonitor.size() > 0)
+ ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
+ : "Got no exceptions on the connection.");
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Provides an assertion that the publisher got a no rout exception on every message.
+ *
+ * @return An assertion that the publisher got a no rout exception on every message.
+ */
+ public Assertion noRouteAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoRouteException.class))
+ {
+ addError("Was expecting linked exception type " + AMQNoRouteException.class.getName()
+ + " on the connection.\n");
+ addError((connectionExceptionMonitor.size() > 0)
+ ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
+ : "Got no exceptions on the connection.");
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Sets the contianing circuit.
+ *
+ * @param circuit The containing circuit.
+ */
+ public void setCircuit(CircuitImpl circuit)
+ {
+ this.circuit = circuit;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java
new file mode 100644
index 0000000000..526537349a
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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.test.framework;
+
+/**
+ * A Receiver is a {@link CircuitEnd} that represents one end of a test circuit. Its main purpose is to
+ * provide assertions that can be applied to test the behaviour of the receiver.
+ */
+public interface Receiver extends CircuitEnd
+{
+ /**
+ * Provides an assertion that the receiver encountered no exceptions.
+ *
+ * @return An assertion that the receiver encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion();
+
+ /**
+ * Provides an assertion that the receiver got all messages that were sent to it.
+ *
+ * @return An assertion that the receiver got all messages that were sent to it.
+ */
+ public Assertion allMessagesAssertion();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/ReceiverImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/ReceiverImpl.java
new file mode 100644
index 0000000000..5f0cb83e63
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/ReceiverImpl.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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.test.framework;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class ReceiverImpl extends CircuitEndBase implements Receiver
+{
+ /** Holds a reference to the containing circuit. */
+ private CircuitImpl circuit;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public ReceiverImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ super(producer, consumer, session);
+ }
+
+ /**
+ * Provides an assertion that the receiver encountered no exceptions.
+ *
+ * @return An assertion that the receiver encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ return null;
+ }
+
+ /**
+ * Provides an assertion that the receiver got all messages that were sent to it.
+ *
+ * @return An assertion that the receiver got all messages that were sent to it.
+ */
+ public Assertion allMessagesAssertion()
+ {
+ return null;
+ }
+
+ /**
+ * Sets the contianing circuit.
+ *
+ * @param circuit The containing circuit.
+ */
+ public void setCircuit(CircuitImpl circuit)
+ {
+ this.circuit = circuit;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java b/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java
new file mode 100644
index 0000000000..60dd4b0f5b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * 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.test.framework;
+
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class TestUtils
+{
+ /**
+ * Establishes a JMS connection using a properties file and qpids built in JNDI implementation. This is a simple
+ * convenience method for code that does anticipate handling connection failures. All exceptions that indicate
+ * that the connection has failed, are wrapped as rutime exceptions, preumably handled by a top level failure
+ * handler.
+ *
+ * @param messagingProps Connection properties as defined in {@link MessagingTestConfigProperties}.
+ *
+ * @return A JMS conneciton.
+ */
+ public static Connection createConnection(ParsedProperties messagingProps)
+ {
+ try
+ {
+ // Extract the configured connection properties from the test configuration.
+ String conUsername = messagingProps.getProperty(USERNAME_PROPNAME);
+ String conPassword = messagingProps.getProperty(PASSWORD_PROPNAME);
+ String virtualHost = messagingProps.getProperty(VIRTUAL_HOST_PROPNAME);
+ String brokerUrl = messagingProps.getProperty(BROKER_PROPNAME);
+
+ // Set up the broker connection url.
+ String connectionString =
+ "amqp://" + conUsername + ":" + conPassword + "/" + ((virtualHost != null) ? virtualHost : "")
+ + "?brokerlist='" + brokerUrl + "'";
+
+ // messagingProps.setProperty(CONNECTION_PROPNAME, connectionString);
+
+ Context ctx = new InitialContext(messagingProps);
+
+ ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CONNECTION_NAME);
+ Connection connection = cf.createConnection();
+
+ return connection;
+ }
+ catch (NamingException e)
+ {
+ throw new RuntimeException("Got JNDI NamingException whilst looking up the connection factory.", e);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Could not establish connection due to JMSException.", e);
+ }
+ }
+
+ /**
+ * Pauses for the specified length of time. In the event of failing to pause for at least that length of time
+ * due to interuption of the thread, a RutimeException is raised to indicate the failure. The interupted status
+ * of the thread is restores in that case. This method should only be used when it is expected that the pause
+ * will be succesfull, for example in test code that relies on inejecting a pause.
+ *
+ * @param t The minimum time to pause for in milliseconds.
+ */
+ public static void pause(long t)
+ {
+ try
+ {
+ Thread.sleep(t);
+ }
+ catch (InterruptedException e)
+ {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+
+ throw new RuntimeException("Failed to generate the requested pause length.", e);
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/package.html b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html
new file mode 100644
index 0000000000..f07a5118e7
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html
@@ -0,0 +1,22 @@
+<html>
+<body>
+<p/>A framework for testing Qpid, built around a standard 'test circuit' design. The idea behind this framework is the
+use of a test circuit which is configured by a set of test parameters, that may be projected onto a topology of
+test nodes, with tests scripted to run over test circuits, making as few assumptions as possible about the underlying
+topology. The standardization of the design, whilst limiting in some respectes, allows a large variety of test
+scenarios to be written with minimal amounts of coding.
+
+<p/>The standard consruction block for a test, is a test circuit. This consists of a publisher, and a receiver. The
+publisher and receiver may reside on the same machine, or may be distributed. Will use a standard set of properties to
+define the desired circuit topology.
+
+<p/>Tests are always to be controlled from the publishing side only. The receiving end of the circuit is to be exposed
+to the test code through an interface, that abstracts as much as possible the receiving end of the test. The interface
+exposes a set of 'assertions' that may be applied to the receiving end of the test circuit.
+
+<p/>In the case where the receiving end of the circuit resides on the same JVM, the assertions will call the receivers
+code locally. Where the receiving end is distributed accross one or more machines, the assertions will be applied to a
+test report gethered from all of the receivers. Test code will be written to the assertions making as few assumptions
+as possible about the exact test topology.
+</body>
+</html> \ No newline at end of file