From f4413e24a4d9e829b9c3775d2bd8ad9aaadde56f Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Fri, 13 Jul 2007 14:24:03 +0000 Subject: 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 --- .../apache/qpid/requestreply/PingPongProducer.java | 30 +- .../qpid/server/exchange/ImmediateMessageTest.java | 758 ++------------------- .../qpid/server/exchange/MandatoryMessageTest.java | 127 ++-- .../exchange/MessagingTestConfigProperties.java | 309 --------- .../org/apache/qpid/test/framework/Assertion.java | 39 ++ .../apache/qpid/test/framework/AssertionBase.java | 66 ++ .../org/apache/qpid/test/framework/Circuit.java | 116 ++++ .../org/apache/qpid/test/framework/CircuitEnd.java | 77 +++ .../apache/qpid/test/framework/CircuitEndBase.java | 119 ++++ .../apache/qpid/test/framework/CircuitImpl.java | 384 +++++++++++ .../qpid/test/framework/ExceptionMonitor.java | 123 ++++ .../qpid/test/framework/FrameworkBaseCase.java | 136 ++++ .../apache/qpid/test/framework/MessageMonitor.java | 36 + .../framework/MessagingTestConfigProperties.java | 309 +++++++++ .../framework/MultiProducerConsumerPairImpl.java | 82 +++ .../org/apache/qpid/test/framework/Publisher.java | 49 ++ .../apache/qpid/test/framework/PublisherImpl.java | 153 +++++ .../org/apache/qpid/test/framework/Receiver.java | 42 ++ .../apache/qpid/test/framework/ReceiverImpl.java | 79 +++ .../org/apache/qpid/test/framework/TestUtils.java | 108 +++ .../org/apache/qpid/test/framework/package.html | 22 + 21 files changed, 2046 insertions(+), 1118 deletions(-) delete mode 100644 java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/CircuitImpl.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/MultiProducerConsumerPairImpl.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/PublisherImpl.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/ReceiverImpl.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java create mode 100644 java/systests/src/main/java/org/apache/qpid/test/framework/package.html (limited to 'java') 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. * * - * @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 exceptions = new ArrayList(); - - 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. - * - *

- *
CRC Card
Responsibilities - *
Provide a message producer for sending messages. - *
Provide a message consumer for receiving messages. - *
- * - * @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. - * - *

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. - * - *

- *
CRC Card
Responsibilities - *
Manage an m*n array of publisher and recievers. - *
- */ - 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; *

Check that a mandatory message is send successfully, in a transactions, when a consumer is * disconnected but when the route exists. * + * + * @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/server/exchange/MessagingTestConfigProperties.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java deleted file mode 100644 index b584c8c80b..0000000000 --- a/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * - * 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.server.exchange; - -import org.apache.qpid.jms.Session; - -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; - -/** - * MessagingTestConfigProperties defines a set of property names and default values for specifying a messaging topology, - * and test parameters for running a messaging test over that topology. A Properties object holding some of these - * properties, superimposed onto the defaults, is used to establish test topologies and control test behaviour. - * - *

A complete list of the parameters, default values and comments on their usage is provided here: - * - *

- *
Parameters
Parameter Default Comments - *
messageSize 0 Message size in bytes. Not including any headers. - *
destinationName ping The root name to use to generate destination names to ping. - *
persistent false Determines whether peristent delivery is used. - *
transacted false Determines whether messages are sent/received in transactions. - *
broker tcp://localhost:5672 Determines the broker to connect to. - *
virtualHost test Determines the virtual host to send all ping over. - *
rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. - *
verbose false The verbose flag for debugging. Prints to console on every message. - *
pubsub false Whether to ping topics or queues. Uses p2p by default. - *
username guest The username to access the broker with. - *
password guest The password to access the broker with. - *
selector null Not used. Defines a message selector to filter pings with. - *
destinationCount 1 The number of receivers listening to the pings. - *
timeout 30000 In milliseconds. The timeout to stop waiting for replies. - *
commitBatchSize 1 The number of messages per transaction in transactional mode. - *
uniqueDests true Whether each receiver only listens to one ping destination or all. - *
durableDests false Whether or not durable destinations are used. - *
ackMode AUTO_ACK The message acknowledgement mode. Possible values are: - * 0 - SESSION_TRANSACTED - * 1 - AUTO_ACKNOWLEDGE - * 2 - CLIENT_ACKNOWLEDGE - * 3 - DUPS_OK_ACKNOWLEDGE - * 257 - NO_ACKNOWLEDGE - * 258 - PRE_ACKNOWLEDGE - *
maxPending 0 The maximum size in bytes, of messages sent but not yet received. - * Limits the volume of messages currently buffered on the client - * or broker. Can help scale test clients by limiting amount of buffered - * data to avoid out of memory errors. - *
- * - *

- *
CRC Card
Responsibilities Collaborations - *
Provide the names and defaults of all test parameters. - *
- */ -public class MessagingTestConfigProperties -{ - // ====================== Connection Properties ================================== - - /** Holds the name of the default connection configuration. */ - public static final String CONNECTION_NAME = "broker"; - - /** Holds the name of the property to get the initial context factory name from. */ - public static final String INITIAL_CONTEXT_FACTORY_PROPNAME = "java.naming.factory.initial"; - - /** Defines the class to use as the initial context factory by default. */ - public static final String INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"; - - /** Holds the name of the default connection factory configuration property. */ - public static final String CONNECTION_PROPNAME = "connectionfactory.broker"; - - /** Defeins the default connection configuration. */ - public static final String CONNECTION_DEFAULT = "amqp://guest:guest@clientid/?brokerlist='vm://:1'"; - - /** Holds the name of the property to get the test broker url from. */ - public static final String BROKER_PROPNAME = "qpid.test.broker"; - - /** Holds the default broker url for the test. */ - public static final String BROKER_DEFAULT = "vm://:1"; - - /** Holds the name of the property to get the test broker virtual path. */ - public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; - - /** Holds the default virtual path for the test. */ - public static final String VIRTUAL_HOST_DEFAULT = ""; - - /** Holds the name of the property to get the broker access username from. */ - public static final String USERNAME_PROPNAME = "username"; - - /** Holds the default broker log on username. */ - public static final String USERNAME_DEFAULT = "guest"; - - /** Holds the name of the property to get the broker access password from. */ - public static final String PASSWORD_PROPNAME = "password"; - - /** Holds the default broker log on password. */ - public static final String PASSWORD_DEFAULT = "guest"; - - // ====================== Messaging Topology Properties ========================== - - /** Holds the name of the property to get the bind publisher procuder flag from. */ - public static final String PUBLISHER_PRODUCER_BIND_PROPNAME = "publisherProducerBind"; - - /** Holds the default value of the publisher producer flag. */ - public static final boolean PUBLISHER_PRODUCER_BIND_DEFAULT = true; - - /** Holds the name of the property to get the bind publisher procuder flag from. */ - public static final String PUBLISHER_CONSUMER_BIND_PROPNAME = "publisherConsumerBind"; - - /** Holds the default value of the publisher consumer flag. */ - public static final boolean PUBLISHER_CONSUMER_BIND_DEFAULT = false; - - /** Holds the name of the property to get the bind receiver procuder flag from. */ - public static final String RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind"; - - /** Holds the default value of the receiver producer flag. */ - public static final boolean RECEIVER_PRODUCER_BIND_DEFAULT = false; - - /** Holds the name of the property to get the bind receiver procuder flag from. */ - public static final String RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind"; - - /** Holds the default value of the receiver consumer flag. */ - public static final boolean RECEIVER_CONSUMER_BIND_DEFAULT = true; - - /** Holds the name of the property to get the destination name root from. */ - public static final String SEND_DESTINATION_NAME_ROOT_PROPNAME = "sendDestinationRoot"; - - /** Holds the root of the name of the default destination to send to. */ - public static final String SEND_DESTINATION_NAME_ROOT_DEFAULT = "sendTo"; - - /** Holds the name of the property to get the destination name root from. */ - public static final String RECEIVE_DESTINATION_NAME_ROOT_PROPNAME = "receiveDestinationRoot"; - - /** Holds the root of the name of the default destination to send to. */ - public static final String RECEIVE_DESTINATION_NAME_ROOT_DEFAULT = "receiveFrom"; - - /** Holds the name of the proeprty to get the destination count from. */ - public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - - /** Defines the default number of destinations to ping. */ - public static final int DESTINATION_COUNT_DEFAULT = 1; - - /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ - public static final String PUBSUB_PROPNAME = "pubsub"; - - /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ - public static final boolean PUBSUB_DEFAULT = false; - - // ====================== JMS Options and Flags ================================= - - /** Holds the name of the property to get the test delivery mode from. */ - public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - - /** Holds the message delivery mode to use for the test. */ - public static final boolean PERSISTENT_MODE_DEFAULT = false; - - /** Holds the name of the property to get the test transactional mode from. */ - public static final String TRANSACTED_PROPNAME = "transacted"; - - /** Holds the transactional mode to use for the test. */ - public static final boolean TRANSACTED_DEFAULT = false; - - /** Holds the name of the property to set the no local flag from. */ - public static final String NO_LOCAL_PROPNAME = "noLocal"; - - /** Defines the default value of the no local flag to use when consuming messages. */ - public static final boolean NO_LOCAL_DEFAULT = false; - - /** Holds the name of the property to get the message acknowledgement mode from. */ - public static final String ACK_MODE_PROPNAME = "ackMode"; - - /** Defines the default message acknowledgement mode. */ - public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - - /** Holds the name of the property to get the durable subscriptions flag from, when doing pub/sub messaging. */ - public static final String DURABLE_SUBSCRIPTION_PROPNAME = "durableSubscription"; - - /** Defines the default value of the durable subscriptions flag. */ - public static final boolean DURABLE_SUBSCRIPTION_DEFAULT = false; - - // ====================== Qpid Options and Flags ================================ - - /** Holds the name of the property to set the exclusive flag from. */ - public static final String EXCLUSIVE_PROPNAME = "exclusive"; - - /** Defines the default value of the exclusive flag to use when consuming messages. */ - public static final boolean EXCLUSIVE_DEFAULT = false; - - /** Holds the name of the property to set the immediate flag from. */ - public static final String IMMEDIATE_PROPNAME = "immediate"; - - /** Defines the default value of the immediate flag to use when sending messages. */ - public static final boolean IMMEDIATE_DEFAULT = false; - - /** Holds the name of the property to set the mandatory flag from. */ - public static final String MANDATORY_PROPNAME = "mandatory"; - - /** Defines the default value of the mandatory flag to use when sending messages. */ - public static final boolean MANDATORY_DEFAULT = false; - - /** Holds the name of the property to get the durable destinations flag from. */ - public static final String DURABLE_DESTS_PROPNAME = "durableDests"; - - /** Default value for the durable destinations flag. */ - public static final boolean DURABLE_DESTS_DEFAULT = false; - - /** Holds the name of the proeprty to set the prefetch size from. */ - public static final String PREFECTH_PROPNAME = "prefetch"; - - /** Defines the default prefetch size to use when consuming messages. */ - public static final int PREFETCH_DEFAULT = 100; - - // ====================== Common Test Parameters ================================ - - /** Holds the name of the property to get the test message size from. */ - public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - - /** Used to set up a default message size. */ - public static final int MESSAGE_SIZE_DEAFULT = 0; - - /** Holds the name of the property to get the message rate from. */ - public static final String RATE_PROPNAME = "rate"; - - /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ - public static final int RATE_DEFAULT = 0; - - /** Holds the name of the proeprty to get the. */ - public static final String SELECTOR_PROPNAME = "selector"; - - /** Holds the default message selector. */ - public static final String SELECTOR_DEFAULT = ""; - - /** Holds the name of the property to get the waiting timeout for response messages. */ - public static final String TIMEOUT_PROPNAME = "timeout"; - - /** Default time to wait before assuming that a ping has timed out. */ - public static final long TIMEOUT_DEFAULT = 30000; - - /** Holds the name of the property to get the commit batch size from. */ - public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - - /** Defines the default number of pings to send in each transaction when running transactionally. */ - public static final int TX_BATCH_SIZE_DEFAULT = 1; - - /** Holds the name of the property to set the maximum amount of pending message data for a producer to hold. */ - public static final String MAX_PENDING_PROPNAME = "maxPending"; - - /** Defines the default maximum quantity of pending message data to allow producers to hold. */ - public static final int MAX_PENDING_DEFAULT = 0; - - /** Holds the name of the property to get the verbose mode proeprty from. */ - public static final String VERBOSE_PROPNAME = "verbose"; - - /** Holds the default verbose mode. */ - public static final boolean VERBOSE_DEFAULT = false; - - /** Holds the default configuration properties. */ - public static ParsedProperties defaults = new ParsedProperties(); - - static - { - defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT); - defaults.setPropertyIfNull(CONNECTION_PROPNAME, CONNECTION_DEFAULT); - defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); - defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT); - defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT); - defaults.setPropertyIfNull(RECEIVER_PRODUCER_BIND_PROPNAME, RECEIVER_PRODUCER_BIND_DEFAULT); - defaults.setPropertyIfNull(RECEIVER_CONSUMER_BIND_PROPNAME, RECEIVER_CONSUMER_BIND_DEFAULT); - defaults.setPropertyIfNull(SEND_DESTINATION_NAME_ROOT_PROPNAME, SEND_DESTINATION_NAME_ROOT_DEFAULT); - defaults.setPropertyIfNull(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME, RECEIVE_DESTINATION_NAME_ROOT_DEFAULT); - defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); - defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); - defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); - defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); - defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); - defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); - defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); - defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); - defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); - defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); - defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); - defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); - defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); - defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); - defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); - defaults.setPropertyIfNull(DURABLE_SUBSCRIPTION_PROPNAME, DURABLE_SUBSCRIPTION_DEFAULT); - defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); - defaults.setPropertyIfNull(PREFECTH_PROPNAME, PREFETCH_DEFAULT); - defaults.setPropertyIfNull(NO_LOCAL_PROPNAME, NO_LOCAL_DEFAULT); - defaults.setPropertyIfNull(EXCLUSIVE_PROPNAME, EXCLUSIVE_DEFAULT); - defaults.setPropertyIfNull(IMMEDIATE_PROPNAME, IMMEDIATE_DEFAULT); - defaults.setPropertyIfNull(MANDATORY_PROPNAME, MANDATORY_DEFAULT); - } -} 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}. + * + *

+ *
CRC Card
Responsibilities + *
Indicate whether or not the assertion passes when applied. + *
+ */ +public interface Assertion +{ + /** + * Applies the assertion. + * + * @return true if the assertion passes, false 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. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
+ *
+ */ +public abstract class AssertionBase implements Assertion +{ + /** Holds the error messages. */ + List errors = new LinkedList(); + + /** + * 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. + * + *

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. + * + *

The state of the circuit may be taken with the {@link #check()} method, and asserted against by the + * {@link #applyAssertions(java.util.List)} method. + * + *

There is a default test procedure which may be performed against the circuit. The outline of this procedure is: + * + *

+ * 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.
+ * 
+ * + *

+ *
CRC Card
Responsibilities + *
Supply the publishing and receiving ends of a test messaging circuit. + *
Start the circuit running. + *
Close the circuit down. + *
Take a reading of the circuits state. + *
Apply assertions against the circuits state. + *
Send test messages over the circuit. + *
Perform the default test procedue on the circuit. + *
+ */ +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 applyAssertions(List 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 test(int numMessages, List 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. + * + *

+ *
CRC Card
Responsibilities + *
Provide a message producer for sending messages. + *
Provide a message consumer for receiving messages. + *
+ * + * @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. + * + *

+ *
CRC Card
Responsibilities + *
Provide a message producer for sending messages. + *
Provide a message consumer for receiving messages. + *
+ */ +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; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
Supply the publishing and receiving ends of a test messaging circuit. + *
Start the circuit running. + *
Close the circuit down. + *
Take a reading of the circuits state. + *
Apply assertions against the circuits state. + *
Send test messages over the circuit. + *
Perform the default test procedue on the circuit. + *
+ */ +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 applyAssertions(List 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: + * + *

+     * 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.
+     * 
+ * + * @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 test(int numMessages, List 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 failures = new LinkedList(); + + 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; + +/** + *

+*
CRC Card
Responsibilities Collaborations +*
+*
+*/ +public class ExceptionMonitor implements ExceptionListener +{ + List exceptions = new ArrayList(); + + 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. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Create and clean up in-vm brokers on every test case. + *
Produce lists of assertions from assertion creation calls. + *
Produce JUnit failures from assertion failures. + *
Convert failed assertions to error messages. + *
+ */ +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 assertionList(Assertion... asserts) + { + List result = new ArrayList(); + + 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 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 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; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
+ *
+ */ +public class MessageMonitor implements MessageListener +{ + public void onMessage(Message message) + { } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java new file mode 100644 index 0000000000..62229f3c72 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java @@ -0,0 +1,309 @@ +/* + * + * 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.jms.Session; + +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; + +/** + * MessagingTestConfigProperties defines a set of property names and default values for specifying a messaging topology, + * and test parameters for running a messaging test over that topology. A Properties object holding some of these + * properties, superimposed onto the defaults, is used to establish test topologies and control test behaviour. + * + *

A complete list of the parameters, default values and comments on their usage is provided here: + * + *

+ *
Parameters
Parameter Default Comments + *
messageSize 0 Message size in bytes. Not including any headers. + *
destinationName ping The root name to use to generate destination names to ping. + *
persistent false Determines whether peristent delivery is used. + *
transacted false Determines whether messages are sent/received in transactions. + *
broker tcp://localhost:5672 Determines the broker to connect to. + *
virtualHost test Determines the virtual host to send all ping over. + *
rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. + *
verbose false The verbose flag for debugging. Prints to console on every message. + *
pubsub false Whether to ping topics or queues. Uses p2p by default. + *
username guest The username to access the broker with. + *
password guest The password to access the broker with. + *
selector null Not used. Defines a message selector to filter pings with. + *
destinationCount 1 The number of receivers listening to the pings. + *
timeout 30000 In milliseconds. The timeout to stop waiting for replies. + *
commitBatchSize 1 The number of messages per transaction in transactional mode. + *
uniqueDests true Whether each receiver only listens to one ping destination or all. + *
durableDests false Whether or not durable destinations are used. + *
ackMode AUTO_ACK The message acknowledgement mode. Possible values are: + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE + *
maxPending 0 The maximum size in bytes, of messages sent but not yet received. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. + *
+ * + *

+ *
CRC Card
Responsibilities Collaborations + *
Provide the names and defaults of all test parameters. + *
+ */ +public class MessagingTestConfigProperties +{ + // ====================== Connection Properties ================================== + + /** Holds the name of the default connection configuration. */ + public static final String CONNECTION_NAME = "broker"; + + /** Holds the name of the property to get the initial context factory name from. */ + public static final String INITIAL_CONTEXT_FACTORY_PROPNAME = "java.naming.factory.initial"; + + /** Defines the class to use as the initial context factory by default. */ + public static final String INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"; + + /** Holds the name of the default connection factory configuration property. */ + public static final String CONNECTION_PROPNAME = "connectionfactory.broker"; + + /** Defeins the default connection configuration. */ + public static final String CONNECTION_DEFAULT = "amqp://guest:guest@clientid/?brokerlist='vm://:1'"; + + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "qpid.test.broker"; + + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "vm://:1"; + + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; + + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; + + /** Holds the name of the property to get the broker access username from. */ + public static final String USERNAME_PROPNAME = "username"; + + /** Holds the default broker log on username. */ + public static final String USERNAME_DEFAULT = "guest"; + + /** Holds the name of the property to get the broker access password from. */ + public static final String PASSWORD_PROPNAME = "password"; + + /** Holds the default broker log on password. */ + public static final String PASSWORD_DEFAULT = "guest"; + + // ====================== Messaging Topology Properties ========================== + + /** Holds the name of the property to get the bind publisher procuder flag from. */ + public static final String PUBLISHER_PRODUCER_BIND_PROPNAME = "publisherProducerBind"; + + /** Holds the default value of the publisher producer flag. */ + public static final boolean PUBLISHER_PRODUCER_BIND_DEFAULT = true; + + /** Holds the name of the property to get the bind publisher procuder flag from. */ + public static final String PUBLISHER_CONSUMER_BIND_PROPNAME = "publisherConsumerBind"; + + /** Holds the default value of the publisher consumer flag. */ + public static final boolean PUBLISHER_CONSUMER_BIND_DEFAULT = false; + + /** Holds the name of the property to get the bind receiver procuder flag from. */ + public static final String RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind"; + + /** Holds the default value of the receiver producer flag. */ + public static final boolean RECEIVER_PRODUCER_BIND_DEFAULT = false; + + /** Holds the name of the property to get the bind receiver procuder flag from. */ + public static final String RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind"; + + /** Holds the default value of the receiver consumer flag. */ + public static final boolean RECEIVER_CONSUMER_BIND_DEFAULT = true; + + /** Holds the name of the property to get the destination name root from. */ + public static final String SEND_DESTINATION_NAME_ROOT_PROPNAME = "sendDestinationRoot"; + + /** Holds the root of the name of the default destination to send to. */ + public static final String SEND_DESTINATION_NAME_ROOT_DEFAULT = "sendTo"; + + /** Holds the name of the property to get the destination name root from. */ + public static final String RECEIVE_DESTINATION_NAME_ROOT_PROPNAME = "receiveDestinationRoot"; + + /** Holds the root of the name of the default destination to send to. */ + public static final String RECEIVE_DESTINATION_NAME_ROOT_DEFAULT = "receiveFrom"; + + /** Holds the name of the proeprty to get the destination count from. */ + public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; + + /** Defines the default number of destinations to ping. */ + public static final int DESTINATION_COUNT_DEFAULT = 1; + + /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ + public static final String PUBSUB_PROPNAME = "pubsub"; + + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + public static final boolean PUBSUB_DEFAULT = false; + + // ====================== JMS Options and Flags ================================= + + /** Holds the name of the property to get the test delivery mode from. */ + public static final String PERSISTENT_MODE_PROPNAME = "persistent"; + + /** Holds the message delivery mode to use for the test. */ + public static final boolean PERSISTENT_MODE_DEFAULT = false; + + /** Holds the name of the property to get the test transactional mode from. */ + public static final String TRANSACTED_PROPNAME = "transacted"; + + /** Holds the transactional mode to use for the test. */ + public static final boolean TRANSACTED_DEFAULT = false; + + /** Holds the name of the property to set the no local flag from. */ + public static final String NO_LOCAL_PROPNAME = "noLocal"; + + /** Defines the default value of the no local flag to use when consuming messages. */ + public static final boolean NO_LOCAL_DEFAULT = false; + + /** Holds the name of the property to get the message acknowledgement mode from. */ + public static final String ACK_MODE_PROPNAME = "ackMode"; + + /** Defines the default message acknowledgement mode. */ + public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + + /** Holds the name of the property to get the durable subscriptions flag from, when doing pub/sub messaging. */ + public static final String DURABLE_SUBSCRIPTION_PROPNAME = "durableSubscription"; + + /** Defines the default value of the durable subscriptions flag. */ + public static final boolean DURABLE_SUBSCRIPTION_DEFAULT = false; + + // ====================== Qpid Options and Flags ================================ + + /** Holds the name of the property to set the exclusive flag from. */ + public static final String EXCLUSIVE_PROPNAME = "exclusive"; + + /** Defines the default value of the exclusive flag to use when consuming messages. */ + public static final boolean EXCLUSIVE_DEFAULT = false; + + /** Holds the name of the property to set the immediate flag from. */ + public static final String IMMEDIATE_PROPNAME = "immediate"; + + /** Defines the default value of the immediate flag to use when sending messages. */ + public static final boolean IMMEDIATE_DEFAULT = false; + + /** Holds the name of the property to set the mandatory flag from. */ + public static final String MANDATORY_PROPNAME = "mandatory"; + + /** Defines the default value of the mandatory flag to use when sending messages. */ + public static final boolean MANDATORY_DEFAULT = false; + + /** Holds the name of the property to get the durable destinations flag from. */ + public static final String DURABLE_DESTS_PROPNAME = "durableDests"; + + /** Default value for the durable destinations flag. */ + public static final boolean DURABLE_DESTS_DEFAULT = false; + + /** Holds the name of the proeprty to set the prefetch size from. */ + public static final String PREFECTH_PROPNAME = "prefetch"; + + /** Defines the default prefetch size to use when consuming messages. */ + public static final int PREFETCH_DEFAULT = 100; + + // ====================== Common Test Parameters ================================ + + /** Holds the name of the property to get the test message size from. */ + public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; + + /** Used to set up a default message size. */ + public static final int MESSAGE_SIZE_DEAFULT = 0; + + /** Holds the name of the property to get the message rate from. */ + public static final String RATE_PROPNAME = "rate"; + + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + public static final int RATE_DEFAULT = 0; + + /** Holds the name of the proeprty to get the. */ + public static final String SELECTOR_PROPNAME = "selector"; + + /** Holds the default message selector. */ + public static final String SELECTOR_DEFAULT = ""; + + /** Holds the name of the property to get the waiting timeout for response messages. */ + public static final String TIMEOUT_PROPNAME = "timeout"; + + /** Default time to wait before assuming that a ping has timed out. */ + public static final long TIMEOUT_DEFAULT = 30000; + + /** Holds the name of the property to get the commit batch size from. */ + public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; + + /** Defines the default number of pings to send in each transaction when running transactionally. */ + public static final int TX_BATCH_SIZE_DEFAULT = 1; + + /** Holds the name of the property to set the maximum amount of pending message data for a producer to hold. */ + public static final String MAX_PENDING_PROPNAME = "maxPending"; + + /** Defines the default maximum quantity of pending message data to allow producers to hold. */ + public static final int MAX_PENDING_DEFAULT = 0; + + /** Holds the name of the property to get the verbose mode proeprty from. */ + public static final String VERBOSE_PROPNAME = "verbose"; + + /** Holds the default verbose mode. */ + public static final boolean VERBOSE_DEFAULT = false; + + /** Holds the default configuration properties. */ + public static ParsedProperties defaults = new ParsedProperties(); + + static + { + defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT); + defaults.setPropertyIfNull(CONNECTION_PROPNAME, CONNECTION_DEFAULT); + defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); + defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT); + defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT); + defaults.setPropertyIfNull(RECEIVER_PRODUCER_BIND_PROPNAME, RECEIVER_PRODUCER_BIND_DEFAULT); + defaults.setPropertyIfNull(RECEIVER_CONSUMER_BIND_PROPNAME, RECEIVER_CONSUMER_BIND_DEFAULT); + defaults.setPropertyIfNull(SEND_DESTINATION_NAME_ROOT_PROPNAME, SEND_DESTINATION_NAME_ROOT_DEFAULT); + defaults.setPropertyIfNull(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME, RECEIVE_DESTINATION_NAME_ROOT_DEFAULT); + defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); + defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); + defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); + defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); + defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); + defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); + defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); + defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); + defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); + defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); + defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); + defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(DURABLE_SUBSCRIPTION_PROPNAME, DURABLE_SUBSCRIPTION_DEFAULT); + defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); + defaults.setPropertyIfNull(PREFECTH_PROPNAME, PREFETCH_DEFAULT); + defaults.setPropertyIfNull(NO_LOCAL_PROPNAME, NO_LOCAL_DEFAULT); + defaults.setPropertyIfNull(EXCLUSIVE_PROPNAME, EXCLUSIVE_DEFAULT); + defaults.setPropertyIfNull(IMMEDIATE_PROPNAME, IMMEDIATE_DEFAULT); + defaults.setPropertyIfNull(MANDATORY_PROPNAME, MANDATORY_DEFAULT); + } +} 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; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
+ *
+ */ +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; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
+ *
+ */ +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; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
+ *
+ */ +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 @@ + + +

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. + +

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. + +

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. + +

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. + + \ No newline at end of file -- cgit v1.2.1