summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRupert Smith <rupertlssmith@apache.org>2007-08-01 16:19:31 +0000
committerRupert Smith <rupertlssmith@apache.org>2007-08-01 16:19:31 +0000
commit6b54ebb02e87cc4cc0a7bcd1d9d820c463f76e7f (patch)
tree8d36febd23837f732c8c026abbdca5bcdcff7626
parent326741e927301ccf036a3ec98718bc622ca9e435 (diff)
downloadqpid-python-6b54ebb02e87cc4cc0a7bcd1d9d820c463f76e7f.tar.gz
Extensive refactoring of the distributed test framework.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/M2@561855 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase1DummyRun.java12
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase2BasicP2P.java18
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase3BasicPubSub.java16
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/CircuitTestCase.java101
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase1DummyRun.java8
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase2BasicP2P.java8
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase3BasicPubSub.java8
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedClientTestCase.java13
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedTestCase.java8
-rw-r--r--java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClient.java119
-rw-r--r--java/perftests/jar-with-dependencies.xml73
-rw-r--r--java/perftests/pom.xml31
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java10
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java14
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/perftests/QpidTestThroughputPerf.java170
-rw-r--r--java/systests/etc/bin/testclients.sh23
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java107
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java107
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java14
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java38
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java7
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java101
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkClientBaseCase.java11
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java65
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java188
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java12
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java6
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java377
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedPublisherImpl.java63
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedReceiverImpl.java53
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/TestClientCircuitEnd.java315
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java179
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java81
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java18
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java31
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java43
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java9
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClientControlledTest.java (renamed from java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropClientTestCase.java)19
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java19
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalCircuitImpl.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java)266
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalPublisherImpl.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java)38
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalReceiverImpl.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java)36
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseCircuitFactory.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java)7
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/CircuitFactory.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java)47
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java75
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutCircuitFactory.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java)60
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropCircuitFactory.java (renamed from java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java)37
-rw-r--r--java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java8
48 files changed, 2304 insertions, 765 deletions
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase1DummyRun.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase1DummyRun.java
index b119d13a3d..45bbfcd148 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase1DummyRun.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase1DummyRun.java
@@ -22,7 +22,7 @@ package org.apache.qpid.interop.clienttestcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.InteropClientTestCase;
+import org.apache.qpid.test.framework.distributedtesting.TestClientControlledTest;
import javax.jms.JMSException;
import javax.jms.Message;
@@ -41,7 +41,7 @@ import javax.jms.Session;
* <tr><td> Generate test reports.
* </table>
*/
-public class TestCase1DummyRun implements InteropClientTestCase
+public class TestCase1DummyRun implements TestClientControlledTest
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(TestCase1DummyRun.class);
@@ -94,8 +94,10 @@ public class TestCase1DummyRun implements InteropClientTestCase
/**
* Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
+ *
+ * @param numMessages The number of test messages to send.
*/
- public void start()
+ public void start(int numMessages)
{
log.debug("public void start(): called");
@@ -105,7 +107,7 @@ public class TestCase1DummyRun implements InteropClientTestCase
/**
* Gets a report on the actions performed by the test case in its assigned role.
*
- * @param session The session to create the report message in.
+ * @param session The controlSession to create the report message in.
*
* @return The report message.
*
@@ -113,7 +115,7 @@ public class TestCase1DummyRun implements InteropClientTestCase
*/
public Message getReport(Session session) throws JMSException
{
- log.debug("public Message getReport(Session session): called");
+ log.debug("public Message getReport(Session controlSession): called");
// Generate a dummy report, the coordinator expects a report but doesn't care what it is.
return session.createTextMessage("Dummy Run, Ok.");
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase2BasicP2P.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase2BasicP2P.java
index 080bd846ee..1d30ff7ca6 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase2BasicP2P.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase2BasicP2P.java
@@ -22,9 +22,9 @@ package org.apache.qpid.interop.clienttestcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.InteropClientTestCase;
-import org.apache.qpid.test.framework.distributedtesting.TestClient;
import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.distributedtesting.TestClient;
+import org.apache.qpid.test.framework.distributedtesting.TestClientControlledTest;
import javax.jms.*;
@@ -41,7 +41,7 @@ import javax.jms.*;
* <tr><td> Generate test reports.
* </table>
*/
-public class TestCase2BasicP2P implements InteropClientTestCase
+public class TestCase2BasicP2P implements TestClientControlledTest, MessageListener
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(TestCase2BasicP2P.class);
@@ -58,7 +58,7 @@ public class TestCase2BasicP2P implements InteropClientTestCase
/** The connection to send the test messages on. */
private Connection connection;
- /** The session to send the test messages on. */
+ /** The controlSession to send the test messages on. */
private Session session;
/** The producer to send the test messages with. */
@@ -147,9 +147,11 @@ public class TestCase2BasicP2P implements InteropClientTestCase
/**
* Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
*
+ * @param numMessages The number of test messages to send.
+ *
* @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
*/
- public void start() throws JMSException
+ public void start(int numMessages) throws JMSException
{
log.debug("public void start(): called");
@@ -158,7 +160,7 @@ public class TestCase2BasicP2P implements InteropClientTestCase
{
Message testMessage = session.createTextMessage("test");
- for (int i = 0; i < numMessages; i++)
+ for (int i = 0; i < this.numMessages; i++)
{
producer.send(testMessage);
@@ -171,7 +173,7 @@ public class TestCase2BasicP2P implements InteropClientTestCase
/**
* Gets a report on the actions performed by the test case in its assigned role.
*
- * @param session The session to create the report message in.
+ * @param session The controlSession to create the report message in.
*
* @return The report message.
*
@@ -179,7 +181,7 @@ public class TestCase2BasicP2P implements InteropClientTestCase
*/
public Message getReport(Session session) throws JMSException
{
- log.debug("public Message getReport(Session session): called");
+ log.debug("public Message getReport(Session controlSession): called");
// Close the test connection.
connection.close();
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase3BasicPubSub.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase3BasicPubSub.java
index a11d045e89..622ddc2f64 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase3BasicPubSub.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/clienttestcases/TestCase3BasicPubSub.java
@@ -22,9 +22,9 @@ package org.apache.qpid.interop.clienttestcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.InteropClientTestCase;
-import org.apache.qpid.test.framework.distributedtesting.TestClient;
import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.distributedtesting.TestClient;
+import org.apache.qpid.test.framework.distributedtesting.TestClientControlledTest;
import javax.jms.*;
@@ -42,7 +42,7 @@ import javax.jms.*;
* <tr><td> Generate test reports.
* </table>
*/
-public class TestCase3BasicPubSub implements InteropClientTestCase
+public class TestCase3BasicPubSub implements TestClientControlledTest, MessageListener
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(TestCase3BasicPubSub.class);
@@ -174,9 +174,11 @@ public class TestCase3BasicPubSub implements InteropClientTestCase
/**
* Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
*
+ * @param numMessages The number of test messages to send.
+ *
* @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
*/
- public void start() throws JMSException
+ public void start(int numMessages) throws JMSException
{
log.debug("public void start(): called");
@@ -185,7 +187,7 @@ public class TestCase3BasicPubSub implements InteropClientTestCase
{
Message testMessage = session[0].createTextMessage("test");
- for (int i = 0; i < numMessages; i++)
+ for (int i = 0; i < this.numMessages; i++)
{
producer.send(testMessage);
@@ -198,7 +200,7 @@ public class TestCase3BasicPubSub implements InteropClientTestCase
/**
* Gets a report on the actions performed by the test case in its assigned role.
*
- * @param session The session to create the report message in.
+ * @param session The controlSession to create the report message in.
*
* @return The report message.
*
@@ -206,7 +208,7 @@ public class TestCase3BasicPubSub implements InteropClientTestCase
*/
public Message getReport(Session session) throws JMSException
{
- log.debug("public Message getReport(Session session): called");
+ log.debug("public Message getReport(Session controlSession): called");
// Close the test connections.
for (Connection conn : connection)
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/CircuitTestCase.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/CircuitTestCase.java
deleted file mode 100644
index 966a545e16..0000000000
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/CircuitTestCase.java
+++ /dev/null
@@ -1,101 +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.interop.testcases;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
-import org.apache.qpid.test.framework.Circuit;
-import org.apache.qpid.test.framework.FrameworkBaseCase;
-import org.apache.qpid.test.framework.MessagingTestConfigProperties;
-
-import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
-
-/**
- * CircuitTestCase runs a test over a {@link Circuit} controlled by the test parameters.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td>
- * </table>
- *
- * @todo When working with test context properties, add overrides to defaults to the singleton instance, but when taking
- * a starting point to add specific test case parameters to, take a copy. Use the copy with test case specifics
- * to control the test.
- */
-public class CircuitTestCase extends FrameworkBaseCase
-{
- /** Used for debugging. */
- private static final Logger log = Logger.getLogger(CircuitTestCase.class);
-
- /**
- * Creates a new test case with the specified name.
- *
- * @param name The test case name.
- */
- public CircuitTestCase(String name)
- {
- super(name);
- }
-
- /**
- * Performs the a basic P2P test case.
- *
- * @throws Exception Any exceptions are allowed to fall through and fail the test.
- */
- public void testBasicP2P() throws Exception
- {
- log.debug("public void testBasicP2P(): called");
-
- // Get the test parameters, any overrides on the command line will have been applied.
- ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
-
- // Customize the test parameters.
- testProps.setProperty("TEST_NAME", "DEFAULT_CIRCUIT_TEST");
- testProps.setProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME, "testqueue");
-
- // Get the test sequencer to create test circuits and run the standard test procedure through.
- TestCaseSequencer sequencer = getTestSequencer();
-
- // Send the test messages, and check that there were no errors doing so.
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
-
- // Check that all of the message were sent.
- // Check that the receiving end got the same number of messages as the publishing end.
- }
-
- /**
- * Should provide a translation from the junit method name of a test to its test case name as known to the test
- * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
- * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
- * name "TC2_BasicP2P".
- *
- * @param methodName The name of the JUnit test method.
- *
- * @return The name of the corresponding interop test case.
- */
- public String getTestCaseNameForTestMethod(String methodName)
- {
- return "DEFAULT_CIRCUIT_TEST";
- }
-}
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase1DummyRun.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase1DummyRun.java
index 73e08b578e..60cd9f47f3 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase1DummyRun.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase1DummyRun.java
@@ -22,7 +22,7 @@ package org.apache.qpid.interop.testcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import java.util.Properties;
@@ -33,10 +33,10 @@ import java.util.Properties;
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* <tr><td> Exercises the interop testing framework without actually sending any test messages.
- * <td> {@link org.apache.qpid.test.framework.distributedtesting.DistributedTestCase}
+ * <td> {@link FrameworkBaseCase}
* </table>
*/
-public class InteropTestCase1DummyRun extends DistributedTestCase
+public class InteropTestCase1DummyRun extends FrameworkBaseCase
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(InteropTestCase1DummyRun.class);
@@ -63,7 +63,7 @@ public class InteropTestCase1DummyRun extends DistributedTestCase
Properties testConfig = new Properties();
testConfig.put("TEST_NAME", "TC1_DummyRun");
- /*Message[] reports =*/ getTestSequencer().sequenceTest(null, null, testConfig);
+ /*Message[] reports =*/ getCircuitFactory().sequenceTest(null, null, testConfig);
// Compare sender and receivers reports.
// Assert.assertEquals("Expected to get 2 dummy reports.", 2, reports.length);
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase2BasicP2P.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase2BasicP2P.java
index f77bbf032f..8983249daa 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase2BasicP2P.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase2BasicP2P.java
@@ -22,7 +22,7 @@ package org.apache.qpid.interop.testcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import java.util.Properties;
@@ -33,10 +33,10 @@ import java.util.Properties;
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Setup p2p test parameters and compare with test output. <td> {@link DistributedTestCase}
+ * <tr><td> Setup p2p test parameters and compare with test output. <td> {@link FrameworkBaseCase}
* </table>
*/
-public class InteropTestCase2BasicP2P extends DistributedTestCase
+public class InteropTestCase2BasicP2P extends FrameworkBaseCase
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(InteropTestCase2BasicP2P.class);
@@ -65,7 +65,7 @@ public class InteropTestCase2BasicP2P extends DistributedTestCase
testConfig.setProperty("P2P_QUEUE_AND_KEY_NAME", "tc2queue");
testConfig.put("P2P_NUM_MESSAGES", 50);
- /*Message[] reports =*/ getTestSequencer().sequenceTest(null, null, testConfig);
+ /*Message[] reports =*/ getCircuitFactory().sequenceTest(null, null, testConfig);
// Compare sender and receivers reports.
/*int messagesSent = reports[0].getIntProperty("MESSAGE_COUNT");
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase3BasicPubSub.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase3BasicPubSub.java
index ad27ca63bd..6e87c3e3ee 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase3BasicPubSub.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/testcases/InteropTestCase3BasicPubSub.java
@@ -22,17 +22,17 @@ package org.apache.qpid.interop.testcases;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import java.util.Properties;
/**
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Setup pub/sub test parameters and compare with test output. <td> {@link DistributedTestCase}
+ * <tr><td> Setup pub/sub test parameters and compare with test output. <td> {@link FrameworkBaseCase}
* </table>
*/
-public class InteropTestCase3BasicPubSub extends DistributedTestCase
+public class InteropTestCase3BasicPubSub extends FrameworkBaseCase
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(InteropTestCase3BasicPubSub.class);
@@ -62,7 +62,7 @@ public class InteropTestCase3BasicPubSub extends DistributedTestCase
testConfig.put("PUBSUB_NUM_MESSAGES", 10);
testConfig.put("PUBSUB_NUM_RECEIVERS", 5);
- /*Message[] reports =*/ getTestSequencer().sequenceTest(null, null, testConfig);
+ /*Message[] reports =*/ getCircuitFactory().sequenceTest(null, null, testConfig);
// Compare sender and receivers reports.
/*int messagesSent = reports[0].getIntProperty("MESSAGE_COUNT");
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedClientTestCase.java b/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedClientTestCase.java
index 65e05fab4b..2764f2c3aa 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedClientTestCase.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedClientTestCase.java
@@ -57,7 +57,7 @@ import java.util.concurrent.CountDownLatch;
* <tr><td> Send required number of test messages using pub/sub. <tr><td> Generate test reports.
* </table>
*/
-public class SustainedClientTestCase extends TestCase3BasicPubSub implements ExceptionListener
+public class SustainedClientTestCase extends TestCase3BasicPubSub implements ExceptionListener, MessageListener
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(SustainedClientTestCase.class);
@@ -205,8 +205,9 @@ public class SustainedClientTestCase extends TestCase3BasicPubSub implements Exc
}
}
- /** Performs the test case actions. */
- public void start() throws JMSException
+ /** Performs the test case actions.
+ * @param numMessages*/
+ public void start(int numMessages) throws JMSException
{
log.debug("public void start(): called");
@@ -235,7 +236,7 @@ public class SustainedClientTestCase extends TestCase3BasicPubSub implements Exc
/**
* Gets a report on the actions performed by the test case in its assigned role.
*
- * @param session The session to create the report message in.
+ * @param session The controlSession to create the report message in.
*
* @return The report message.
*
@@ -243,7 +244,7 @@ public class SustainedClientTestCase extends TestCase3BasicPubSub implements Exc
*/
public Message getReport(Session session) throws JMSException
{
- log.debug("public Message getReport(Session session): called");
+ log.debug("public Message getReport(Session controlSession): called");
// Close the test connections.
for (int i = 0; i < connection.length; i++)
@@ -318,7 +319,7 @@ public class SustainedClientTestCase extends TestCase3BasicPubSub implements Exc
* @param clientname The _client id used to identify this connection.
* @param batchSize The number of messages that are to be sent per batch. Note: This is not used to
* control the interval between sending reports.
- * @param session The session used for communication.
+ * @param session The controlSession used for communication.
* @param sendDestination The destination that update reports should be sent to.
*
* @throws JMSException My occur if creatingthe Producer fails
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedTestCase.java b/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedTestCase.java
index 36f9b4eaf1..5979a459ec 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedTestCase.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/sustained/SustainedTestCase.java
@@ -23,8 +23,8 @@ package org.apache.qpid.sustained;
import org.apache.log4j.Logger;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
import org.apache.qpid.test.framework.DropInTest;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import javax.jms.JMSException;
import javax.jms.Message;
@@ -32,7 +32,7 @@ import javax.jms.Message;
import java.util.Properties;
/**
- * SustainedTestCase is a {@link org.apache.qpid.test.framework.distributedtesting.DistributedTestCase} that runs the "Perf_SustainedPubSub" test case. This consists of one
+ * SustainedTestCase is a {@link FrameworkBaseCase} that runs the "Perf_SustainedPubSub" test case. This consists of one
* test client sending, and several receiving, and attempts to find the highest rate at which messages can be broadcast
* to the receivers. It is also a {@link DropInTest} to which more test clients may be added during a test run.
*
@@ -41,7 +41,7 @@ import java.util.Properties;
* <tr><td>
* </table>
*/
-public class SustainedTestCase extends DistributedTestCase implements DropInTest
+public class SustainedTestCase extends FrameworkBaseCase implements DropInTest
{
/** Used for debugging. */
Logger log = Logger.getLogger(SustainedTestCase.class);
@@ -78,7 +78,7 @@ public class SustainedTestCase extends DistributedTestCase implements DropInTest
log.info("Created Config: " + testConfig.entrySet().toArray());
- getTestSequencer().sequenceTest(null, null, testConfig);
+ getCircuitFactory().sequenceTest(null, null, testConfig);
}
/**
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClient.java b/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClient.java
index 12c0d0aa69..6e726c53bb 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClient.java
+++ b/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClient.java
@@ -21,6 +21,7 @@
package org.apache.qpid.test.framework.distributedtesting;
import org.apache.log4j.Logger;
+import org.apache.log4j.NDC;
import org.apache.qpid.interop.clienttestcases.TestCase1DummyRun;
import org.apache.qpid.interop.clienttestcases.TestCase2BasicP2P;
@@ -28,17 +29,14 @@ import org.apache.qpid.interop.clienttestcases.TestCase3BasicPubSub;
import org.apache.qpid.sustained.SustainedClientTestCase;
import org.apache.qpid.test.framework.MessagingTestConfigProperties;
import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.distributedcircuit.TestClientCircuitEnd;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
import javax.jms.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
/**
* Implements a test client as described in the interop testing spec
@@ -57,8 +55,8 @@ import java.util.Map;
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Handle all incoming control messages. <td> {@link InteropClientTestCase}
- * <tr><td> Configure and look up test cases by name. <td> {@link InteropClientTestCase}
+ * <tr><td> Handle all incoming control messages. <td> {@link TestClientControlledTest}
+ * <tr><td> Configure and look up test cases by name. <td> {@link TestClientControlledTest}
* </table>
*/
public class TestClient implements MessageListener
@@ -86,10 +84,10 @@ public class TestClient implements MessageListener
TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
/** Holds all the test cases loaded from the classpath. */
- Map<String, InteropClientTestCase> testCases = new HashMap<String, InteropClientTestCase>();
+ Map<String, TestClientControlledTest> testCases = new HashMap<String, TestClientControlledTest>();
/** Holds the test case currently being run by this client. */
- protected InteropClientTestCase currentTestCase;
+ protected TestClientControlledTest currentTestCase;
/** Holds the connection to the broker that the test is being coordinated on. */
protected Connection connection;
@@ -97,7 +95,7 @@ public class TestClient implements MessageListener
/** Holds the message producer to hold the test coordination over. */
protected MessageProducer producer;
- /** Holds the JMS session for the test coordination. */
+ /** Holds the JMS controlSession for the test coordination. */
protected Session session;
/** Holds the name of this client, with a default value. */
@@ -113,11 +111,12 @@ public class TestClient implements MessageListener
* @param brokerUrl The url of the broker to connect to.
* @param virtualHost The virtual host to conect to.
* @param clientName The client name to use.
+ * @param join Flag to indicate that this client should attempt to join running tests.
*/
public TestClient(String brokerUrl, String virtualHost, String clientName, boolean join)
{
- log.debug("public SustainedTestClient(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost
- + ", String clientName = " + clientName + "): called");
+ log.debug("public TestClient(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost
+ + ", String clientName = " + clientName + ", boolean join = " + join + "): called");
// Retain the connection parameters.
this.brokerUrl = brokerUrl;
@@ -140,6 +139,9 @@ public class TestClient implements MessageListener
*/
public static void main(String[] args)
{
+ log.debug("public static void main(String[] args = " + Arrays.toString(args) + "): called");
+ console.info("Qpid Distributed Test Client.");
+
// Override the default broker url to be localhost:5672.
testContextProperties.setProperty(MessagingTestConfigProperties.BROKER_PROPNAME, "tcp://localhost:5672");
@@ -163,18 +165,22 @@ public class TestClient implements MessageListener
String brokerUrl = options.getProperty("b");
String virtualHost = options.getProperty("h");
String clientName = options.getProperty("n");
+ clientName = (clientName == null) ? CLIENT_NAME : clientName;
boolean join = options.getPropertyAsBoolean("j");
+ // To distinguish logging output set up an NDC on the client name.
+ NDC.push(clientName);
+
// Create a test client and start it running.
- TestClient client = new TestClient(brokerUrl, virtualHost, (clientName == null) ? CLIENT_NAME : clientName, join);
+ TestClient client = new TestClient(brokerUrl, virtualHost, clientName, join);
// Use a class path scanner to find all the interop test case implementations.
// Hard code the test classes till the classpath scanner is fixed.
- Collection<Class<? extends InteropClientTestCase>> testCaseClasses =
- new ArrayList<Class<? extends InteropClientTestCase>>();
- // ClasspathScanner.getMatches(InteropClientTestCase.class, "^TestCase.*", true);
+ Collection<Class<? extends TestClientControlledTest>> testCaseClasses =
+ new ArrayList<Class<? extends TestClientControlledTest>>();
+ // ClasspathScanner.getMatches(TestClientControlledTest.class, "^TestCase.*", true);
Collections.addAll(testCaseClasses, TestCase1DummyRun.class, TestCase2BasicP2P.class, TestCase3BasicPubSub.class,
- SustainedClientTestCase.class);
+ SustainedClientTestCase.class, TestClientCircuitEnd.class);
try
{
@@ -183,6 +189,7 @@ public class TestClient implements MessageListener
catch (Exception e)
{
log.error("The test client was unable to start.", e);
+ console.info(e.getMessage());
System.exit(1);
}
}
@@ -195,16 +202,17 @@ public class TestClient implements MessageListener
*
* @throws JMSException Any underlying JMSExceptions are allowed to fall through.
*/
- protected void start(Collection<Class<? extends InteropClientTestCase>> testCaseClasses) throws JMSException
+ protected void start(Collection<Class<? extends TestClientControlledTest>> testCaseClasses) throws JMSException
{
- log.debug("private void start(): called");
+ log.debug("protected void start(Collection<Class<? extends TestClientControlledTest>> testCaseClasses = "
+ + testCaseClasses + "): called");
// Create all the test case implementations and index them by the test names.
- for (Class<? extends InteropClientTestCase> nextClass : testCaseClasses)
+ for (Class<? extends TestClientControlledTest> nextClass : testCaseClasses)
{
try
{
- InteropClientTestCase testCase = nextClass.newInstance();
+ TestClientControlledTest testCase = nextClass.newInstance();
testCases.put(testCase.getName(), testCase);
}
catch (InstantiationException e)
@@ -259,6 +267,7 @@ public class TestClient implements MessageListener
*/
public void onMessage(Message message)
{
+ NDC.push(clientName);
log.debug("public void onMessage(Message message = " + message + "): called");
try
@@ -266,7 +275,7 @@ public class TestClient implements MessageListener
String controlType = message.getStringProperty("CONTROL_TYPE");
String testName = message.getStringProperty("TEST_NAME");
- log.info("onMessage(Message message = " + message + "): for '" + controlType + "' to '" + testName + "'");
+ log.debug("Received control of type '" + controlType + "' for the test '" + testName + "'");
// Check if the message is a test invite.
if ("INVITE".equals(controlType))
@@ -280,13 +289,21 @@ public class TestClient implements MessageListener
log.debug("Got an invite to test: " + testName);
// Check if the requested test case is available.
- InteropClientTestCase testCase = testCases.get(testName);
+ TestClientControlledTest testCase = testCases.get(testName);
if (testCase != null)
{
+ log.debug("Found implementing class for test '" + testName + "', enlisting for it.");
+
+ // Check if the test case will accept the invitation.
+ enlist = testCase.acceptInvite(message);
+
+ log.debug("The test case "
+ + (enlist ? " accepted the invite, enlisting for it."
+ : " did not accept the invite, not enlisting."));
+
// Make the requested test case the current test case.
currentTestCase = testCase;
- enlist = true;
}
else
{
@@ -295,7 +312,7 @@ public class TestClient implements MessageListener
}
else
{
- log.debug("Got a compulsory invite.");
+ log.debug("Got a compulsory invite, enlisting for it.");
enlist = true;
}
@@ -309,7 +326,20 @@ public class TestClient implements MessageListener
enlistMessage.setStringProperty("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
enlistMessage.setJMSCorrelationID(message.getJMSCorrelationID());
- log.info("Sending Message '" + enlistMessage + "'. to " + message.getJMSReplyTo());
+ log.debug("Sending enlist message '" + enlistMessage + "' to " + message.getJMSReplyTo());
+
+ producer.send(message.getJMSReplyTo(), enlistMessage);
+ }
+ else
+ {
+ // Reply with the client name in an Decline message.
+ Message enlistMessage = session.createMessage();
+ enlistMessage.setStringProperty("CONTROL_TYPE", "DECLINE");
+ enlistMessage.setStringProperty("CLIENT_NAME", clientName);
+ enlistMessage.setStringProperty("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
+ enlistMessage.setJMSCorrelationID(message.getJMSCorrelationID());
+
+ log.debug("Sending decline message '" + enlistMessage + "' to " + message.getJMSReplyTo());
producer.send(message.getJMSReplyTo(), enlistMessage);
}
@@ -321,15 +351,18 @@ public class TestClient implements MessageListener
log.debug("Got a role assignment to role: " + roleName);
- InteropClientTestCase.Roles role = Enum.valueOf(InteropClientTestCase.Roles.class, roleName);
+ TestClientControlledTest.Roles role = Enum.valueOf(TestClientControlledTest.Roles.class, roleName);
currentTestCase.assignRole(role, message);
// Reply by accepting the role in an Accept Role message.
Message acceptRoleMessage = session.createMessage();
+ acceptRoleMessage.setStringProperty("CLIENT_NAME", clientName);
acceptRoleMessage.setStringProperty("CONTROL_TYPE", "ACCEPT_ROLE");
acceptRoleMessage.setJMSCorrelationID(message.getJMSCorrelationID());
+ log.debug("Sending accept role message '" + acceptRoleMessage + "' to " + message.getJMSReplyTo());
+
producer.send(message.getJMSReplyTo(), acceptRoleMessage);
}
else if ("START".equals(controlType) || "STATUS_REQUEST".equals(controlType))
@@ -338,8 +371,21 @@ public class TestClient implements MessageListener
{
log.debug("Got a start notification.");
+ // Extract the number of test messages to send from the start notification.
+ int numMessages;
+
+ try
+ {
+ numMessages = message.getIntProperty("MESSAGE_COUNT");
+ }
+ catch (JMSException e)
+ {
+ // If the number of messages is not specified, use the default of one.
+ numMessages = 1;
+ }
+
// Start the current test case.
- currentTestCase.start();
+ currentTestCase.start(numMessages);
}
else
{
@@ -348,9 +394,12 @@ public class TestClient implements MessageListener
// Generate the report from the test case and reply with it as a Report message.
Message reportMessage = currentTestCase.getReport(session);
+ reportMessage.setStringProperty("CLIENT_NAME", clientName);
reportMessage.setStringProperty("CONTROL_TYPE", "REPORT");
reportMessage.setJMSCorrelationID(message.getJMSCorrelationID());
+ log.debug("Sending report message '" + reportMessage + "' to " + message.getJMSReplyTo());
+
producer.send(message.getJMSReplyTo(), reportMessage);
}
else if ("TERMINATE".equals(controlType))
@@ -370,8 +419,18 @@ public class TestClient implements MessageListener
catch (JMSException e)
{
// Log a warning about this, but otherwise ignore it.
- log.warn("A JMSException occurred whilst handling a message.");
- log.debug("Got JMSException whilst handling message: " + message, e);
+ log.warn("Got JMSException whilst handling message: " + message, e);
+ }
+ // Log any runtimes that fall through this message handler. These are fatal errors for the test client.
+ catch (RuntimeException e)
+ {
+ log.error("The test client message handler got an unhandled exception: ", e);
+ console.info("The message handler got an unhandled exception, terminating the test client.");
+ System.exit(1);
+ }
+ finally
+ {
+ NDC.pop();
}
}
}
diff --git a/java/perftests/jar-with-dependencies.xml b/java/perftests/jar-with-dependencies.xml
index 3e95e7ab22..959473f535 100644
--- a/java/perftests/jar-with-dependencies.xml
+++ b/java/perftests/jar-with-dependencies.xml
@@ -16,32 +16,51 @@
specific language governing permissions and limitations
under the License.
-->
-<!-- This is an assembly descriptor that produces a jar file that contains all the
- dependencies, fully expanded into a single jar, required to run the tests of
- a maven project.
- -->
+<!-- This is an assembly descriptor that produces a distribution that contains all the
+ dependencies, with a manifest only jar that references them, required to run the
+ tests of a maven project.
+-->
<assembly>
- <id>all-test-deps</id>
- <formats>
- <format>jar</format>
- </formats>
- <includeBaseDirectory>false</includeBaseDirectory>
- <dependencySets>
- <dependencySet>
- <outputDirectory></outputDirectory>
- <outputFileNameMapping></outputFileNameMapping>
- <unpack>true</unpack>
- <scope>test</scope>
- </dependencySet>
- </dependencySets>
- <fileSets>
- <fileSet>
- <directory>target/classes</directory>
- <outputDirectory></outputDirectory>
- </fileSet>
- <fileSet>
- <directory>target/test-classes</directory>
- <outputDirectory></outputDirectory>
- </fileSet>
- </fileSets>
+ <id>all-test-deps</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>target/classes</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ <fileSet>
+ <directory>target/test-classes</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+
+ <!-- Include the build artifact. -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>qpid-perftests-1.0-incubating-M2-SNAPSHOT.jar</include>
+ </includes>
+ </fileSet>
+
+ <!-- Include the classpath only jar. -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>qpid-perftests-1.0-incubating-M2-SNAPSHOT-tests.jar</include>
+ </includes>
+ </fileSet>
+
+ </fileSets>
</assembly>
diff --git a/java/perftests/pom.xml b/java/perftests/pom.xml
index e07b0696e5..41bd6c1a84 100644
--- a/java/perftests/pom.xml
+++ b/java/perftests/pom.xml
@@ -72,6 +72,11 @@
</dependency>
<dependency>
+ <groupId>org.apache.qpid</groupId>
+ <artifactId>qpid-systests</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
@@ -85,9 +90,10 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>compile</scope>
</dependency>
- <dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.0</version>
@@ -354,13 +360,34 @@
<configuration>
<descriptors>
<descriptor>jar-with-dependencies.xml</descriptor>
- <descriptor>dist-zip.xml</descriptor>
+ <!--<descriptor>dist-zip.xml</descriptor>-->
</descriptors>
<outputDirectory>target</outputDirectory>
<workDirectory>target/assembly/work</workDirectory>
</configuration>
</plugin>
+ <!-- Build a manifest only jar with all the required jars for the broker in its classpath. -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>test_jar</id>
+ <configuration>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ </manifest>
+ </archive>
+ </configuration>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
</plugins>
<resources>
diff --git a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
index 78ab7c4c73..82b36bf233 100644
--- a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
+++ b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
@@ -92,10 +92,10 @@ public class PingPongBouncer implements MessageListener
/** The producer for sending replies with. */
private MessageProducer _replyProducer;
- /** The consumer session. */
+ /** The consumer controlSession. */
private Session _consumerSession;
- /** The producer session. */
+ /** The producer controlSession. */
private Session _producerSession;
/** Holds the connection to the broker. */
@@ -149,7 +149,7 @@ public class PingPongBouncer implements MessageListener
// Set up the failover notifier.
getConnection().setConnectionListener(new FailoverNotifier());
- // Create a session to listen for messages on and one to send replies on, transactional depending on the
+ // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the
// command line option.
_consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
_producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
@@ -323,8 +323,8 @@ public class PingPongBouncer implements MessageListener
}
/**
- * Convenience method to commit the transaction on the specified session. If the session to commit on is not
- * a transactional session, this method does nothing.
+ * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not
+ * a transactional controlSession, this method does nothing.
*
* <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
* commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
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 03f5f0549d..140e3bad1c 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
@@ -395,10 +395,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis
/** Holds the connection to the broker. */
protected Connection _connection;
- /** Holds the session on which ping replies are received. */
+ /** Holds the controlSession on which ping replies are received. */
protected Session _consumerSession;
- /** Holds the producer session, needed to create ping messages. */
+ /** Holds the producer controlSession, needed to create ping messages. */
protected Session _producerSession;
/** Holds the destination where the response messages will arrive. */
@@ -1305,8 +1305,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis
}
/**
- * Convenience method to commit the transaction on the specified session. If the session to commit on is not a
- * transactional session, this method does nothing (unless the failover after send flag is set).
+ * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a
+ * transactional controlSession, this method does nothing (unless the failover after send flag is set).
*
* <p/>If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is
* applied. This flag applies whether the pinger is transactional or not.
@@ -1315,9 +1315,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis
* is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the
* commit is applied. These flags will only apply if using a transactional pinger.
*
- * @param session The session to commit
+ * @param session The controlSession to commit
*
- * @return <tt>true</tt> if the session was committed, <tt>false</tt> if it was not.
+ * @return <tt>true</tt> if the controlSession was committed, <tt>false</tt> if it was not.
*
* @throws javax.jms.JMSException If the commit fails and then the rollback fails.
*
@@ -1327,7 +1327,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis
*/
protected boolean commitTx(Session session) throws JMSException
{
- // log.debug("protected void commitTx(Session session): called");
+ // log.debug("protected void commitTx(Session controlSession): called");
boolean committed = false;
diff --git a/java/perftests/src/test/java/org/apache/qpid/perftests/QpidTestThroughputPerf.java b/java/perftests/src/test/java/org/apache/qpid/perftests/QpidTestThroughputPerf.java
new file mode 100644
index 0000000000..760d1c84a4
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/perftests/QpidTestThroughputPerf.java
@@ -0,0 +1,170 @@
+/*
+ *
+ * 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.perftests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
+
+import uk.co.thebadgerset.junit.extensions.TestThreadAware;
+import uk.co.thebadgerset.junit.extensions.TimingController;
+import uk.co.thebadgerset.junit.extensions.TimingControllerAware;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
+
+import java.util.LinkedList;
+
+/**
+ * QpidTestThroughputPerf runs a test over a {@link Circuit} controlled by the test parameters. It logs timings of
+ * the time required to receive samples consisting of batches of messages. As the time samples is taken over a reasonable
+ * sized message batch, it measures message throughput.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ *
+ * @todo Check that all of the messages were sent. Check that the receiving end got the same number of messages as
+ * the publishing end.
+ */
+public class QpidTestThroughputPerf extends FrameworkBaseCase implements TimingControllerAware, TestThreadAware
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(QpidTestThroughputPerf.class);
+
+ /** Holds the timing controller, used to log test timings from self-timed tests. */
+ private TimingController timingController;
+
+ /** Thread local to hold the per-thread test setup fields. */
+ ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
+
+ /**
+ * Creates a new test case with the specified name.
+ *
+ * @param name The test case name.
+ */
+ public QpidTestThroughputPerf(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Performs the a basic P2P test case.
+ *
+ * @param numMessages The number of messages to send in the test.
+ */
+ public void testThroughput(int numMessages)
+ {
+ log.debug("public void testThroughput(): called");
+
+ PerThreadSetup setup = threadSetup.get();
+ assertNoFailures(setup.testCircuit.test(numMessages, new LinkedList<Assertion>()));
+ }
+
+ /**
+ * Should provide a translation from the junit method name of a test to its test case name as known to the test
+ * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
+ * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
+ * name "TC2_BasicP2P".
+ *
+ * @param methodName The name of the JUnit test method.
+ *
+ * @return The name of the corresponding interop test case.
+ */
+ public String getTestCaseNameForTestMethod(String methodName)
+ {
+ log.debug("public String getTestCaseNameForTestMethod(String methodName = " + methodName + "): called");
+
+ return "DEFAULT_CIRCUIT_TEST";
+ }
+
+ /**
+ * Used by test runners that can supply a {@link uk.co.thebadgerset.junit.extensions.TimingController} to set the
+ * controller on an aware test.
+ *
+ * @param controller The timing controller.
+ */
+ public void setTimingController(TimingController controller)
+ {
+ timingController = controller;
+ }
+
+ /**
+ * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
+ */
+ public void threadSetUp()
+ {
+ // Get the test parameters, any overrides on the command line will have been applied.
+ ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
+
+ // Customize the test parameters.
+ testProps.setProperty("TEST_NAME", "DEFAULT_CIRCUIT_TEST");
+ testProps.setProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME, "testqueue");
+
+ // Get the test circuit factory to create test circuits and run the standard test procedure through.
+ CircuitFactory circuitFactory = getCircuitFactory();
+
+ // Create the test circuit. This projects the circuit onto the available test nodes and connects it up.
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ // Store the test configuration for the thread.
+ PerThreadSetup setup = new PerThreadSetup();
+ setup.testCircuit = testCircuit;
+ threadSetup.set(setup);
+ }
+
+ /**
+ * Called when a test thread is destroyed.
+ */
+ public void threadTearDown()
+ { }
+
+ /**
+ * Holds the per-thread test configurations.
+ */
+ protected static class PerThreadSetup
+ {
+ /** Holds the test circuit to run tests on. */
+ Circuit testCircuit;
+ }
+
+ /**
+ * Compiles all the tests in this class into a suite.
+ *
+ * @return The test suite.
+ */
+ public static Test suite()
+ {
+ // Build a new test suite
+ TestSuite suite = new TestSuite("Qpid Throughput Performance Tests");
+
+ suite.addTest(new QpidTestThroughputPerf("testThroughput"));
+
+ return suite;
+ }
+}
diff --git a/java/systests/etc/bin/testclients.sh b/java/systests/etc/bin/testclients.sh
new file mode 100644
index 0000000000..4b10c833de
--- /dev/null
+++ b/java/systests/etc/bin/testclients.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# 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.
+#
+for x in `seq 1 $1`;
+do
+ java -cp qpid-integrationtests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar -Dlog4j.configuration=file:/home/rupert/qpid/trunk/qpid/java/etc/mylog4j.xml org.apache.qpid.test.framework.distributedtesting.TestClient -n $x &
+done
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 4a0a27bb06..9b5c9c3d00 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,11 +20,11 @@
*/
package org.apache.qpid.server.exchange;
-import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
import org.apache.qpid.test.framework.Circuit;
import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.MessagingTestConfigProperties;
import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
@@ -85,9 +85,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, false);
// Run the default test sequence over the test circuit checking for no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
@@ -98,43 +99,44 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, false);
// Send one message with no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
- public void test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P() throws Exception
+ public void test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
+ 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. */
- public void test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P() throws Exception
+ public void test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no route code, not using transactions, when no outgoing route is connected. */
@@ -149,9 +151,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is connected. */
@@ -166,9 +169,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message is sent succesfully not using transactions when a consumer is connected. */
@@ -179,9 +183,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, true);
// Send one message with no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
@@ -192,13 +197,14 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, true);
// Send one message with no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
- public void test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -207,18 +213,18 @@ public class ImmediateMessageTest extends FrameworkBaseCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
+ 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. */
- public void test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -227,14 +233,14 @@ public class ImmediateMessageTest extends FrameworkBaseCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message and get a linked no consumers exception.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noConsumersAssertion())));
}
/** Check that an immediate message results in no route code, not using transactions, when no outgoing route is connected. */
@@ -249,9 +255,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is connected. */
@@ -266,9 +273,10 @@ public class ImmediateMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
protected void setUp() throws Exception
@@ -283,5 +291,6 @@ public class ImmediateMessageTest extends FrameworkBaseCase
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, true);
}
}
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 94a33806d0..df99d044d2 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,11 +20,11 @@
*/
package org.apache.qpid.server.exchange;
-import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
import org.apache.qpid.test.framework.Circuit;
import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.MessagingTestConfigProperties;
import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
@@ -85,9 +85,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, false);
// Run the default test sequence over the test circuit checking for no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
@@ -98,49 +99,50 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, false);
// Run the default test sequence over the test circuit checking for no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
* Check that a mandatory message is sent succesfully, not using transactions, when a consumer is disconnected but
* the route exists.
*/
- public void test_QPID_517_MandatoryOkConsumerDisconnectedNoTxP2P() throws Exception
+ public void test_QPID_517_MandatoryOkConsumerDisconnectedNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message with no errors.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
* Check that a mandatory message is sent succesfully, in a transaction, when a consumer is disconnected but
* the route exists.
*/
- public void test_QPID_517_MandatoryOkConsumerDisconnectedTxP2P() throws Exception
+ public void test_QPID_517_MandatoryOkConsumerDisconnectedTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message with no errors.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), 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. */
@@ -155,9 +157,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ 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. */
@@ -172,9 +175,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
/** Check that an mandatory message is sent succesfully not using transactions when a consumer is connected. */
@@ -185,9 +189,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, true);
// Run the default test sequence over the test circuit checking for no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(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. */
@@ -198,16 +203,17 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(PUBSUB_PROPNAME, true);
// Run the default test sequence over the test circuit checking for no errors.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
* Check that a mandatory message is sent succesfully, not using transactions, when a consumer is disconnected but
* the route exists.
*/
- public void test_QPID_517_MandatoryOkConsumerDisconnectedNoTxPubSub() throws Exception
+ public void test_QPID_517_MandatoryOkConsumerDisconnectedNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
@@ -216,21 +222,21 @@ public class MandatoryMessageTest extends FrameworkBaseCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message with no errors.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noExceptionsAssertion())));
}
/**
* Check that a mandatory message is sent succesfully, in a transaction, when a consumer is disconnected but
* the route exists.
*/
- public void test_QPID_517_MandatoryOkConsumerDisconnectedTxPubSub() throws Exception
+ public void test_QPID_517_MandatoryOkConsumerDisconnectedTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
@@ -239,14 +245,14 @@ public class MandatoryMessageTest extends FrameworkBaseCase
// Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
-
// Disconnect the consumer.
- testCircuit.getReceiver().getConsumer().close();
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, false);
+
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
// Send one message with no errors.
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), 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. */
@@ -261,9 +267,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ 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. */
@@ -278,9 +285,10 @@ public class MandatoryMessageTest extends FrameworkBaseCase
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
// Send one message and get a linked no route exception.
- TestCaseSequencer sequencer = getTestSequencer();
- Circuit testCircuit = sequencer.createCircuit(testProps);
- sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
+ CircuitFactory circuitFactory = getCircuitFactory();
+ Circuit testCircuit = circuitFactory.createCircuit(testProps);
+
+ assertNoFailures(testCircuit.test(1, assertionList(testCircuit.getPublisher().noRouteAssertion())));
}
protected void setUp() throws Exception
@@ -295,5 +303,6 @@ public class MandatoryMessageTest extends FrameworkBaseCase
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
+ testProps.setProperty(RECEIVER_CONSUMER_ACTIVE_PROPNAME, true);
}
}
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
index 43c3fa4c66..e557620cf5 100644
--- 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
@@ -74,4 +74,18 @@ public interface CircuitEnd
* @throws JMSException Any JMSExceptions occurring during the close are allowed to fall through.
*/
public void close() throws JMSException;
+
+ /**
+ * Returns the message monitor for reporting on received messages on this circuit end.
+ *
+ * @return The message monitor for this circuit end.
+ */
+ public MessageMonitor getMessageMonitor();
+
+ /**
+ * Returns the exception monitor for reporting on exceptions received on this circuit end.
+ *
+ * @return The exception monitor for this circuit end.
+ */
+ public ExceptionMonitor getExceptionMonitor();
}
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
index 54a30d9c6e..251b216c45 100644
--- 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
@@ -41,21 +41,31 @@ public class CircuitEndBase implements CircuitEnd
/** Holds the single message consumer. */
MessageConsumer consumer;
- /** Holds the session for the circuit end. */
+ /** Holds the controlSession for the circuit end. */
Session session;
+ /** Holds the message monitor for the circuit end. */
+ MessageMonitor messageMonitor;
+
+ /** Holds the exception monitor for the circuit end. */
+ ExceptionMonitor exceptionMonitor;
+
/**
- * Creates a circuit end point on the specified producer, consumer and session.
+ * Creates a circuit end point on the specified producer, consumer and controlSession.
*
* @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.
+ * @param session The controlSession for the circuit end point.
*/
- public CircuitEndBase(MessageProducer producer, MessageConsumer consumer, Session session)
+ public CircuitEndBase(MessageProducer producer, MessageConsumer consumer, Session session, MessageMonitor messageMonitor,
+ ExceptionMonitor exceptionMonitor)
{
this.producer = producer;
this.consumer = consumer;
this.session = session;
+
+ this.messageMonitor = messageMonitor;
+ this.exceptionMonitor = exceptionMonitor;
}
/**
@@ -116,4 +126,24 @@ public class CircuitEndBase implements CircuitEnd
consumer.close();
}
}
+
+ /**
+ * Returns the message monitor for reporting on received messages on this circuit end.
+ *
+ * @return The message monitor for this circuit end.
+ */
+ public MessageMonitor getMessageMonitor()
+ {
+ return messageMonitor;
+ }
+
+ /**
+ * Returns the exception monitor for reporting on exceptions received on this circuit end.
+ *
+ * @return The exception monitor for this circuit end.
+ */
+ 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
index 606f2eabda..437b2cc142 100644
--- 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
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.test.framework;
+import org.apache.log4j.Logger;
+
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
@@ -39,6 +41,9 @@ import java.util.List;
*/
public class ExceptionMonitor implements ExceptionListener
{
+ /** Used for debugging. */
+ private final Logger log = Logger.getLogger(ExceptionMonitor.class);
+
/** Holds the received exceptions. */
List<JMSException> exceptions = new ArrayList<JMSException>();
@@ -49,6 +54,8 @@ public class ExceptionMonitor implements ExceptionListener
*/
public void onException(JMSException e)
{
+ log.debug("public void onException(JMSException e): called");
+
exceptions.add(e);
}
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
index d6cb0cad13..77bb7a5c52 100644
--- 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
@@ -22,13 +22,16 @@ package org.apache.qpid.test.framework;
import junit.framework.TestCase;
+import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
+import org.apache.qpid.test.framework.localcircuit.LocalCircuitImpl;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
+import org.apache.qpid.util.ConversationFactory;
+import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import java.util.ArrayList;
@@ -47,10 +50,13 @@ import java.util.Properties;
* <tr><td> Convert failed assertions to error messages.
* </table>
*/
-public class FrameworkBaseCase extends TestCase
+public class FrameworkBaseCase extends AsymptoticTestCase
{
+ /** Used for debugging purposes. */
+ private static final Logger log = Logger.getLogger(FrameworkBaseCase.class);
+
/** Holds the test sequencer to create and run test circuits with. */
- protected TestCaseSequencer testSequencer = new DefaultTestSequencer();
+ protected CircuitFactory circuitFactory = new DefaultCircuitFactory();
/**
* Creates a new test case with the specified name.
@@ -69,20 +75,20 @@ public class FrameworkBaseCase extends TestCase
*
* @return The test case sequencer.
*/
- protected TestCaseSequencer getTestSequencer()
+ protected CircuitFactory getCircuitFactory()
{
- return testSequencer;
+ return circuitFactory;
}
/**
- * Overrides the default test sequencer. Test decorators can use this to supply distributed test sequencers or other
- * test sequencer specializations.
+ * Overrides the default test circuit factory. Test decorators can use this to supply distributed test sequencers or
+ * other test circuit factory specializations.
*
- * @param sequencer The new test sequencer.
+ * @param circuitFactory The new test circuit factory.
*/
- public void setTestSequencer(TestCaseSequencer sequencer)
+ public void setCircuitFactory(CircuitFactory circuitFactory)
{
- this.testSequencer = sequencer;
+ this.circuitFactory = circuitFactory;
}
/**
@@ -112,6 +118,8 @@ public class FrameworkBaseCase extends TestCase
*/
protected void assertNoFailures(List<Assertion> asserts)
{
+ log.debug("protected void assertNoFailures(List<Assertion> asserts = " + asserts + "): called");
+
// Check if there are no assertion failures, and return without doing anything if so.
if ((asserts == null) || asserts.isEmpty())
{
@@ -175,10 +183,25 @@ public class FrameworkBaseCase extends TestCase
}
/**
- * DefaultTestSequencer is a test sequencer that creates test circuits with publishing and receiving ends rooted
+ * Should provide a translation from the junit method name of a test to its test case name as known to the test
+ * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
+ * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
+ * name "TC2_BasicP2P".
+ *
+ * @param methodName The name of the JUnit test method.
+ *
+ * @return The name of the corresponding interop test case.
+ */
+ public String getTestCaseNameForTestMethod(String methodName)
+ {
+ return methodName;
+ }
+
+ /**
+ * DefaultCircuitFactory is a test sequencer that creates test circuits with publishing and receiving ends rooted
* on the same JVM.
*/
- public class DefaultTestSequencer implements TestCaseSequencer
+ public class DefaultCircuitFactory implements CircuitFactory
{
/**
* Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
@@ -201,7 +224,57 @@ public class FrameworkBaseCase extends TestCase
*/
public Circuit createCircuit(ParsedProperties testProperties)
{
- return CircuitImpl.createCircuit(testProperties);
+ return LocalCircuitImpl.createCircuit(testProperties);
+ }
+
+ /**
+ * Sets the sender test client to coordinate the test with.
+ *
+ * @param sender The contact details of the sending client in the test.
+ */
+ public void setSender(TestClientDetails sender)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Sets the receiving test client to coordinate the test with.
+ *
+ * @param receiver The contact details of the sending client in the test.
+ */
+ public void setReceiver(TestClientDetails receiver)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Supplies the sending test client.
+ *
+ * @return The sending test client.
+ */
+ public TestClientDetails getSender()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Supplies the receiving test client.
+ *
+ * @return The receiving test client.
+ */
+ public List<TestClientDetails> getReceivers()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Accepts the conversation factory over which to hold the test coordinating conversation.
+ *
+ * @param conversationFactory The conversation factory to coordinate the test over.
+ */
+ public void setConversationFactory(ConversationFactory conversationFactory)
+ {
+ throw new RuntimeException("Not implemented.");
}
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkClientBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkClientBaseCase.java
new file mode 100644
index 0000000000..2456ba1709
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkClientBaseCase.java
@@ -0,0 +1,11 @@
+package org.apache.qpid.test.framework;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class FrameworkClientBaseCase
+{
+}
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
index 873f876012..245b6fa7fd 100644
--- 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
@@ -20,27 +20,86 @@
*/
package org.apache.qpid.test.framework;
+import org.apache.log4j.Logger;
+
import javax.jms.Message;
import javax.jms.MessageListener;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* MessageMonitor is used to record information about messages received. This will provide methods to check various
* properties, such as the type, number and content of messages received in order to verify the correct behaviour of
* tests.
*
- * <p/>At the moment this monitor does not do anything.
- *
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Count incoming messages.
+ * <tr><td> Record time ellapsed since the arrival of the first message.
+ * <tr><td> Reset all counts and timings.
* </table>
*/
public class MessageMonitor implements MessageListener
{
+ /** Used for debugging. */
+ private final Logger log = Logger.getLogger(MessageMonitor.class);
+
+ /** Holds the count of messages received since the last query. */
+ protected AtomicInteger numMessages = new AtomicInteger();
+
+ /** Holds the time of arrival of the first message. */
+ protected Long firstMessageTime = null;
+
/**
* Handles received messages. Does Nothing.
*
* @param message The message. Ignored.
*/
public void onMessage(Message message)
- { }
+ {
+ log.debug("public void onMessage(Message message): called");
+
+ numMessages.getAndIncrement();
+ }
+
+ /**
+ * Gets the count of messages.
+ *
+ * @return The count of messages.
+ */
+ public int getNumMessage()
+ {
+ if (firstMessageTime == null)
+ {
+ firstMessageTime = System.nanoTime();
+ }
+
+ return numMessages.get();
+ }
+
+ /**
+ * Gets the time elapsed since the first message arrived, in nanos, or zero if no messages have arrived yet.
+ *
+ * @return The time elapsed since the first message arrived, in nanos, or zero if no messages have arrived yet.
+ */
+ public long getTime()
+ {
+ if (firstMessageTime != null)
+ {
+ return System.nanoTime() - firstMessageTime;
+ }
+ else
+ {
+ return 0L;
+ }
+ }
+
+ /**
+ * Resets the message count and timer to zero.
+ */
+ public void reset()
+ {
+ numMessages.set(0);
+ firstMessageTime = null;
+ }
}
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
index 3cc4a92886..f6664a78d9 100644
--- 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
@@ -24,6 +24,8 @@ import org.apache.qpid.jms.Session;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+import java.util.Properties;
+
/**
* 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
@@ -67,8 +69,11 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
* <tr><th> Responsibilities <th> Collaborations
* <tr><td> Provide the names and defaults of all test parameters.
* </table>
+ *
+ * @todo Put a type-safe wrapper around these properties, but continue to store the parameters as properties. This is
+ * simply to ensure that it is a simple matter to serialize/deserialize string/string pairs onto messages.
*/
-public class MessagingTestConfigProperties
+public class MessagingTestConfigProperties extends ParsedProperties
{
// ====================== Connection Properties ==================================
@@ -131,6 +136,18 @@ public class MessagingTestConfigProperties
/** Holds the default value of the receivers consumer flag. */
public static final boolean RECEIVER_CONSUMER_BIND_DEFAULT = true;
+ /** Holds the name of the property to get the publishers consumer active flag from. */
+ public static final String PUBLISHER_CONSUMER_ACTIVE_PROPNAME = "publisherConsumerActive";
+
+ /** Holds the default value of the publishers consumer active flag. */
+ public static final boolean PUBLISHER_CONSUMER_ACTIVE_DEFAULT = true;
+
+ /** Holds the name of the property to get the receivers consumer active flag from. */
+ public static final String RECEIVER_CONSUMER_ACTIVE_PROPNAME = "receiverConsumerActive";
+
+ /** Holds the default value of the receivers consumer active flag. */
+ public static final boolean RECEIVER_CONSUMER_ACTIVE_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";
@@ -214,7 +231,7 @@ public class MessagingTestConfigProperties
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";
+ public static final String PREFETCH_PROPNAME = "prefetch";
/** Defines the default prefetch size to use when consuming messages. */
public static final int PREFETCH_DEFAULT = 100;
@@ -275,6 +292,8 @@ public class MessagingTestConfigProperties
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(PUBLISHER_CONSUMER_ACTIVE_PROPNAME, PUBLISHER_CONSUMER_ACTIVE_DEFAULT);
+ defaults.setPropertyIfNull(RECEIVER_CONSUMER_ACTIVE_PROPNAME, RECEIVER_CONSUMER_ACTIVE_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);
@@ -294,10 +313,173 @@ public class MessagingTestConfigProperties
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(PREFETCH_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);
}
+
+ /**
+ * Creates a test configuration based on the defaults.
+ */
+ public MessagingTestConfigProperties()
+ {
+ super(defaults);
+ }
+
+ /**
+ * Creates a test configuration based on the supplied properties.
+ *
+ * @param properties The test configuration.
+ */
+ public MessagingTestConfigProperties(Properties properties)
+ {
+ super(properties);
+ }
+
+ public int getMessageSize()
+ {
+ return getPropertyAsInteger(MESSAGE_SIZE_PROPNAME);
+ }
+
+ public boolean getPublisherProducerBind()
+ {
+ return getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
+ }
+
+ public boolean getPublisherConsumerBind()
+ {
+ return getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
+ }
+
+ public boolean getReceiverProducerBind()
+ {
+ return getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
+ }
+
+ public boolean getReceiverConsumerBind()
+ {
+ return getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
+ }
+
+ public boolean getPublisherConsumerActive()
+ {
+ return getPropertyAsBoolean(PUBLISHER_CONSUMER_ACTIVE_PROPNAME);
+ }
+
+ public boolean getReceiverConsumerActive()
+ {
+ return getPropertyAsBoolean(RECEIVER_CONSUMER_ACTIVE_PROPNAME);
+ }
+
+ public String getSendDestinationNameRoot()
+ {
+ return getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME);
+ }
+
+ public String getReceiveDestinationNameRoot()
+ {
+ return getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME);
+ }
+
+ public boolean getPersistentMode()
+ {
+ return getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME);
+ }
+
+ public boolean getTransacted()
+ {
+ return getPropertyAsBoolean(TRANSACTED_PROPNAME);
+ }
+
+ public String getBroker()
+ {
+ return getProperty(BROKER_PROPNAME);
+ }
+
+ public String getVirtualHost()
+ {
+ return getProperty(VIRTUAL_HOST_PROPNAME);
+ }
+
+ public String getRate()
+ {
+ return getProperty(RATE_PROPNAME);
+ }
+
+ public boolean getPubsub()
+ {
+ return getPropertyAsBoolean(PUBSUB_PROPNAME);
+ }
+
+ public String getUsername()
+ {
+ return getProperty(USERNAME_PROPNAME);
+ }
+
+ public String getPassword()
+ {
+ return getProperty(PASSWORD_PROPNAME);
+ }
+
+ public int getDestinationCount()
+ {
+ return getPropertyAsInteger(DESTINATION_COUNT_PROPNAME);
+ }
+
+ public long getTimeout()
+ {
+ return getPropertyAsLong(TIMEOUT_PROPNAME);
+ }
+
+ public int getTxBatchSize()
+ {
+ return getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME);
+ }
+
+ public boolean getDurableDests()
+ {
+ return getPropertyAsBoolean(DURABLE_DESTS_PROPNAME);
+ }
+
+ public int getAckMode()
+ {
+ return getPropertyAsInteger(ACK_MODE_PROPNAME);
+ }
+
+ public boolean getDurableSubscription()
+ {
+ return getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
+ }
+
+ public int getMaxPending()
+ {
+ return getPropertyAsInteger(MAX_PENDING_PROPNAME);
+ }
+
+ public int getPrefecth()
+ {
+ return getPropertyAsInteger(PREFETCH_PROPNAME);
+ }
+
+ public boolean getNoLocal()
+ {
+ return getPropertyAsBoolean(NO_LOCAL_PROPNAME);
+ }
+
+ public boolean getExclusive()
+ {
+ return getPropertyAsBoolean(EXCLUSIVE_PROPNAME);
+ }
+
+ public boolean getImmediate()
+ {
+ return getPropertyAsBoolean(IMMEDIATE_PROPNAME);
+ }
+
+ public boolean getMandatory()
+ {
+ return getPropertyAsBoolean(MANDATORY_PROPNAME);
+ }
}
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
index 59aa9065dd..df35579533 100644
--- 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
@@ -21,17 +21,17 @@
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.
+ * A Publisher is a {@link CircuitEnd} that represents the status of the publishing side of a test circuit. Its main
+ * purpose is to provide assertions that can be applied to test the behaviour of the publishers.
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities
- * <tr><td> Provide assertion that the publisher received no exceptions.
- * <tr><td> Provide assertion that the publisher received a no consumers error code.
- * <tr><td> Provide assertion that the publisher received a no route error code.
+ * <tr><td> Provide assertion that the publishers received no exceptions.
+ * <tr><td> Provide assertion that the publishers received a no consumers error code on every message.
+ * <tr><td> Provide assertion that the publishers received a no route error code on every message.
* </table>
*/
-public interface Publisher extends CircuitEnd
+public interface Publisher
{
/**
* Provides an assertion that the publisher encountered no exceptions.
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
index 6e01a7ea4f..e01b272d5a 100644
--- 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
@@ -21,8 +21,8 @@
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 receivers.
+ * A Receiver is a {@link CircuitEnd} that represents the status of the receiving side of a test circuit. Its main
+ * purpose is to provide assertions that can be applied to check the behaviour of the receivers.
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities
@@ -30,7 +30,7 @@ package org.apache.qpid.test.framework;
* <tr><td> Provide assertion that the receivers received all test messages sent to it.
* </table>
*/
-public interface Receiver extends CircuitEnd
+public interface Receiver
{
/**
* Provides an assertion that the receivers encountered no exceptions.
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java
index aadd378aed..921d16c998 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java
@@ -20,11 +20,21 @@
*/
package org.apache.qpid.test.framework.distributedcircuit;
-import org.apache.qpid.test.framework.Assertion;
-import org.apache.qpid.test.framework.Circuit;
-import org.apache.qpid.test.framework.Publisher;
-import org.apache.qpid.test.framework.Receiver;
+import org.apache.log4j.Logger;
+import org.apache.qpid.test.framework.*;
+import org.apache.qpid.util.ConversationFactory;
+
+import uk.co.thebadgerset.junit.extensions.TimingController;
+import uk.co.thebadgerset.junit.extensions.TimingControllerAware;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import java.util.LinkedList;
import java.util.List;
/**
@@ -42,9 +52,199 @@ import java.util.List;
* <tr><td> Send test messages over the circuit.
* <tr><td> Perform the default test procedue on the circuit.
* </table>
+ *
+ * @todo There is a short pause after receiving sender reports before asking for receiver reports, because receivers may
+ * not have finished receiving all their test messages before the report request arrives. This is going to be a
+ * problem for taking test timings and needs to be eliminiated. Suggested solution: have receiver send back reports
+ * asynchronously, on test batch size boundaries, and do so automatically rather than having to have the report
+ * request sent to them. Number each test run, or otherwise uniquely identify it, when a receiver does not get
+ * any more messages on a test run for more than a timeout, it can assume the test is complete and send a final
+ * report. On the coordinator end a future will need to be created to wait for all final reports to come in, and
+ * to register results and timings for the test. This must work in such a way that a new test cycle can be started
+ * without waiting for the results of the old one to come in.
+ *
+ * @todo Test circuits to be created per test thread, not per test method call. Per-thread setup and tear down to be
+ * reposible for circuit creation and clean up. Many individual test method calls to run over the same circuit.
+ * Important, otherwise test results will be skewed by circuit creation overheads.
+ *
*/
-public class DistributedCircuitImpl implements Circuit
+public class DistributedCircuitImpl implements Circuit, TimingControllerAware
{
+ /** Used for debugging purposes. */
+ private static Logger log = Logger.getLogger(DistributedCircuitImpl.class);
+
+ /** Holds the conversation factory over which to coordinate the test. */
+ protected ConversationFactory conversationFactory;
+
+ /** Holds the controlSession over which to hold the control conversation. */
+ protected Session controlSession;
+
+ /** Holds the sender nodes in the test circuit. */
+ protected List<TestClientDetails> senders;
+
+ /** Holds the receiver nodes in the test circuit. */
+ protected List<TestClientDetails> receivers;
+
+ /** Holds the sender control conversations. */
+ protected ConversationFactory.Conversation[] senderConversation;
+
+ /** Holds the receiver control conversations. */
+ protected ConversationFactory.Conversation[] receiverConversation;
+
+ /** Holds the control topics for the senders in the test circuit. */
+ protected Destination[] senderControlTopic;
+
+ /** Holds the control topics for the receivers in the test circuit. */
+ protected Destination[] receiverControlTopic;
+
+ /** Holds the number of messages to send per test run. */
+ protected int numMessages;
+
+ /**
+ * Holds the timing controller for the circuit. This is used to log test times asynchronously, when reciever nodes
+ * return their reports after senders have completed a test case.
+ */
+ TimingController timingController;
+
+ /**
+ * Creates a distributed test circuit on the specified senders and receivers.
+ *
+ * @param session The controlSession for all control conversations.
+ * @param senders The senders.
+ * @param receivers The receivers.
+ * @param senderConversation A control conversation with the senders.
+ * @param receiverConversation A control conversation with the receivers.
+ * @param senderControlTopic The senders control topic.
+ * @param receiverControlTopic The receivers control topic.
+ */
+ protected DistributedCircuitImpl(Session session, List<TestClientDetails> senders, List<TestClientDetails> receivers,
+ ConversationFactory.Conversation[] senderConversation, ConversationFactory.Conversation[] receiverConversation,
+ Destination[] senderControlTopic, Destination[] receiverControlTopic)
+ {
+ this.controlSession = session;
+ this.senders = senders;
+ this.receivers = receivers;
+ this.senderConversation = senderConversation;
+ this.receiverConversation = receiverConversation;
+ this.senderControlTopic = senderControlTopic;
+ this.receiverControlTopic = receiverControlTopic;
+ }
+
+ /**
+ * Creates a distributed test circuit from the specified test parameters, on the senders and receivers
+ * given.
+ *
+ * @param testProps The test parameters.
+ * @param senders The sender ends in the test circuit.
+ * @param receivers The receiver ends in the test circuit.
+ * @param conversationFactory A conversation factory for creating the control conversations with senders and receivers.
+ *
+ * @return A connected and ready to start, test circuit.
+ */
+ public static Circuit createCircuit(ParsedProperties testProps, List<TestClientDetails> senders,
+ List<TestClientDetails> receivers, ConversationFactory conversationFactory)
+ {
+ log.debug("public static Circuit createCircuit(ParsedProperties testProps, List<TestClientDetails> senders, "
+ + " List<TestClientDetails> receivers, ConversationFactory conversationFactory)");
+
+ try
+ {
+ Session session = conversationFactory.getSession();
+
+ // Create control conversations with each of the senders.
+ ConversationFactory.Conversation[] senderConversation = new ConversationFactory.Conversation[senders.size()];
+ Destination[] senderControlTopic = new Destination[senders.size()];
+
+ for (int i = 0; i < senders.size(); i++)
+ {
+ TestClientDetails sender = senders.get(i);
+
+ senderControlTopic[i] = session.createTopic(sender.privateControlKey);
+ senderConversation[i] = conversationFactory.startConversation();
+ }
+
+ log.debug("Sender conversations created.");
+
+ // Create control conversations with each of the receivers.
+ ConversationFactory.Conversation[] receiverConversation = new ConversationFactory.Conversation[receivers.size()];
+ Destination[] receiverControlTopic = new Destination[receivers.size()];
+
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ TestClientDetails receiver = receivers.get(i);
+
+ receiverControlTopic[i] = session.createTopic(receiver.privateControlKey);
+ receiverConversation[i] = conversationFactory.startConversation();
+ }
+
+ log.debug("Receiver conversations created.");
+
+ // Assign the sender role to each of the sending test clients.
+ for (int i = 0; i < senders.size(); i++)
+ {
+ TestClientDetails sender = senders.get(i);
+
+ Message assignSender = conversationFactory.getSession().createMessage();
+ TestUtils.setPropertiesOnMessage(assignSender, testProps);
+ assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignSender.setStringProperty("ROLE", "SENDER");
+
+ senderConversation[i].send(senderControlTopic[i], assignSender);
+ }
+
+ log.debug("Sender role assignments sent.");
+
+ // Assign the receivers role to each of the receiving test clients.
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ TestClientDetails receiver = receivers.get(i);
+
+ Message assignReceiver = session.createMessage();
+ TestUtils.setPropertiesOnMessage(assignReceiver, testProps);
+ assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignReceiver.setStringProperty("ROLE", "RECEIVER");
+
+ receiverConversation[i].send(receiverControlTopic[i], assignReceiver);
+ }
+
+ log.debug("Receiver role assignments sent.");
+
+ // Wait for the senders and receivers to confirm their roles.
+ for (int i = 0; i < senders.size(); i++)
+ {
+ senderConversation[i].receive();
+ }
+
+ log.debug("Got all sender role confirmations");
+
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ receiverConversation[i].receive();
+ }
+
+ log.debug("Got all receiver role confirmations");
+
+ // Package everything up as a circuit.
+ return new DistributedCircuitImpl(session, senders, receivers, senderConversation, receiverConversation,
+ senderControlTopic, receiverControlTopic);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("JMSException not handled.");
+ }
+ }
+
+ /**
+ * Used by tests cases that can supply a {@link uk.co.thebadgerset.junit.extensions.TimingController} to set the
+ * controller on an aware test.
+ *
+ * @param controller The timing controller.
+ */
+ public void setTimingController(TimingController controller)
+ {
+ this.timingController = controller;
+ }
+
/**
* Gets the interface on the publishing end of the circuit.
*
@@ -70,16 +270,132 @@ public class DistributedCircuitImpl implements Circuit
*/
public void start()
{
- throw new RuntimeException("Not Implemented.");
+ log.debug("public void start(): called");
+
+ try
+ {
+ // Start the test on each of the senders.
+ Message start = controlSession.createMessage();
+ start.setStringProperty("CONTROL_TYPE", "START");
+ start.setIntProperty("MESSAGE_COUNT", numMessages);
+
+ for (int i = 0; i < senders.size(); i++)
+ {
+ senderConversation[i].send(senderControlTopic[i], start);
+ }
+
+ log.debug("All senders told to start their tests.");
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unhandled JMSException.", e);
+ }
}
/**
* 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.
+ *
+ * @todo Replace the asynch receiver report thread with a choice of direct os asynch executor, so that asynch
+ * or synch logging of test timings is optional. Also need to provide an onMessage method that is capable
+ * of receiving timing reports that receivers will generate during an ongoing test, on the test sample
+ * size boundaries. The message timing logging code should be factored out as a common method that can
+ * be called in response to the final report responses, or the onMessage method. Another alternative is
+ * to abandon the final report request altogether and just use the onMessage method? I think the two
+ * differ though, as the final report is used to apply assertions, and the ongoing report is just for
+ * periodic timing results... In which case, maybe there needs to be a way for the onMessage method
+ * to process just some of the incoming messages, and forward the rest on to the conversion helper, as
+ * a sort of pre-conversation helper filter?
*/
public void check()
{
- throw new RuntimeException("Not Implemented.");
+ log.debug("public void check(): called");
+
+ try
+ {
+ // Wait for all the test senders to return their reports.
+ for (int i = 0; i < senders.size(); i++)
+ {
+ Message senderReport = senderConversation[i].receive();
+ log.debug("Sender " + senderReport.getStringProperty("CLIENT_NAME") + " reports message count: "
+ + senderReport.getIntProperty("MESSAGE_COUNT"));
+ log.debug("Sender " + senderReport.getStringProperty("CLIENT_NAME") + " reports message time: "
+ + senderReport.getLongProperty("TEST_TIME"));
+ }
+
+ log.debug("Got all sender test reports.");
+
+ // Apply sender assertions to pass/fail the tests.
+
+ // Inject a short pause to give the receivers time to finish receiving their test messages.
+ TestUtils.pause(500);
+
+ // Ask the receivers for their reports.
+ Message statusRequest = controlSession.createMessage();
+ statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");
+
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ receiverConversation[i].send(receiverControlTopic[i], statusRequest);
+ }
+
+ log.debug("All receiver test reports requested.");
+
+ // Wait for all receiver reports to come in, but do so asynchronously.
+ Runnable gatherAllReceiverReports =
+ new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ // Wait for all the receivers to send their reports.
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ Message receiverReport = receiverConversation[i].receive();
+
+ String clientName = receiverReport.getStringProperty("CLIENT_NAME");
+ int messageCount = receiverReport.getIntProperty("MESSAGE_COUNT");
+ long testTime = receiverReport.getLongProperty("TEST_TIME");
+
+ log.debug("Receiver " + clientName + " reports message count: " + messageCount);
+ log.debug("Receiver " + receiverReport.getStringProperty("CLIENT_NAME")
+ + " reports message time: " + testTime);
+
+ // Apply receiver assertions to pass/fail the tests.
+
+ // Log the test timings on the asynchronous test timing controller.
+ try
+ {
+ timingController.completeTest(true, messageCount, testTime);
+ }
+ // The timing controll can throw InterruptedException is the current test is to be
+ // interrupted.
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ log.debug("All receiver test reports received.");
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ Thread receiverReportsThread = new Thread(gatherAllReceiverReports);
+ receiverReportsThread.start();
+
+ // return new Message[] { senderReport, receiverReport };
+
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unhandled JMSException.", e);
+ }
}
/**
@@ -87,19 +403,34 @@ public class DistributedCircuitImpl implements Circuit
*/
public void close()
{
- throw new RuntimeException("Not Implemented.");
+ log.debug("public void close(): called");
+
+ // End the current test on all senders and receivers.
}
/**
- * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * Applies a list of assertions against the test circuit. The {@link #check()} method should be called before doing
* this, to ensure that the circuit has gathered its state into a report to assert against.
*
* @param assertions The list of assertions to apply.
+ *
* @return Any assertions that failed.
*/
public List<Assertion> applyAssertions(List<Assertion> assertions)
{
- throw new RuntimeException("Not Implemented.");
+ log.debug("public List<Assertion> applyAssertions(List<Assertion> assertions = " + assertions + "): called");
+
+ List<Assertion> failures = new LinkedList<Assertion>();
+
+ for (Assertion assertion : assertions)
+ {
+ if (!assertion.apply())
+ {
+ failures.add(assertion);
+ }
+ }
+
+ return failures;
}
/**
@@ -107,10 +438,34 @@ public class DistributedCircuitImpl implements Circuit
*
* @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.
+ *
+ * @todo From check onwards needs to be handled as a future. The future must call back onto the test case to
+ * report results asynchronously.
*/
public List<Assertion> test(int numMessages, List<Assertion> assertions)
{
- throw new RuntimeException("Not Implemented.");
+ log.debug("public List<Assertion> test(int numMessages = " + numMessages + ", List<Assertion> assertions = "
+ + assertions + "): called");
+
+ // Keep the number of messages to send per test run, where the send method can reference it.
+ this.numMessages = numMessages;
+
+ // Start the test running on all sender circuit ends.
+ start();
+
+ // Request status reports to be handed in.
+ check();
+
+ // Assert conditions on the publishing end of the circuit.
+ // Assert conditions on the receiving end of the circuit.
+ List<Assertion> failures = applyAssertions(assertions);
+
+ // Close the circuit ending the current test case.
+ close();
+
+ // Pass with no failed assertions or fail with a list of failed assertions.
+ return failures;
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedPublisherImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedPublisherImpl.java
new file mode 100644
index 0000000000..9e3054964c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedPublisherImpl.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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.distributedcircuit;
+
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Publisher;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class DistributedPublisherImpl implements Publisher
+{
+ /**
+ * Provides an assertion that the publisher encountered no exceptions.
+ *
+ * @return An assertion that the publisher encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * 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()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * 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()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedReceiverImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedReceiverImpl.java
new file mode 100644
index 0000000000..4a77906448
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedReceiverImpl.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.distributedcircuit;
+
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Receiver;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class DistributedReceiverImpl implements Receiver
+{
+ /**
+ * Provides an assertion that the receivers encountered no exceptions.
+ *
+ * @return An assertion that the receivers encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Provides an assertion that the receivers got all messages that were sent to it.
+ *
+ * @return An assertion that the receivers got all messages that were sent to it.
+ */
+ public Assertion allMessagesAssertion()
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/TestClientCircuitEnd.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/TestClientCircuitEnd.java
new file mode 100644
index 0000000000..bf0499314a
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/TestClientCircuitEnd.java
@@ -0,0 +1,315 @@
+/*
+ *
+ * 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.distributedcircuit;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.*;
+import org.apache.qpid.test.framework.distributedtesting.TestClientControlledTest;
+import org.apache.qpid.test.framework.localcircuit.LocalCircuitImpl;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
+
+import javax.jms.*;
+
+/**
+ * A TestClientCircuitEnd is a {@link CircuitEnd} that may be controlled from a
+ * {@link org.apache.qpid.test.framework.distributedtesting.TestClient}, and that forms a single publishing or
+ * receiving end point in a distributed test {@link org.apache.qpid.test.framework.Circuit}.
+ *
+ * <p/>When operating in the SENDER role, this circuit end is capable of acting as part of the default circuit test
+ * procedure (described in the class comment for {@link org.apache.qpid.test.framework.Circuit}). That is, it will
+ * send the number of test messages required, using the test configuration parameters given in the test invite, and
+ * return a report on its activities to the circuit controller.
+ *
+ * <p/>When operation in the RECEIVER role, this circuit end acts as part of the default circuit test procedure. It will
+ * receive test messages, on the setup specified in the test configuration parameters, and keep count of the messages
+ * received, and time taken to receive them. When requested by the circuit controller to provide a report, it will
+ * return this report of its activities.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class TestClientCircuitEnd implements CircuitEnd, TestClientControlledTest
+{
+ /** Used for debugging. */
+ Logger log = Logger.getLogger(TestClientCircuitEnd.class);
+
+ /** Holds the test parameters. */
+ ParsedProperties testProps;
+
+ /** The number of test messages to send. */
+ private int numMessages;
+
+ /** The role to be played by the test. */
+ private Roles role;
+
+ /** The connection to send the test messages on. */
+ private Connection connection;
+
+ /** Holds the circuit end for this test. */
+ CircuitEnd circuitEnd;
+
+ /**
+ * Holds a message monitor for this circuit end, either the monitor on the consumer when in RECEIVER more, or
+ * a monitor updated on every message sent, when acting as a SENDER.
+ */
+ MessageMonitor messageMonitor;
+
+ /**
+ * Should provide the name of the test case that this class implements. The exact names are defined in the
+ * interop testing spec.
+ *
+ * @return The name of the test case that this implements.
+ */
+ public String getName()
+ {
+ return "DEFAULT_CIRCUIT_TEST";
+ }
+
+ /**
+ * Determines whether the test invite that matched this test case is acceptable.
+ *
+ * @param inviteMessage The invitation to accept or reject.
+ * @return <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public boolean acceptInvite(Message inviteMessage) throws JMSException
+ {
+ log.debug("public boolean acceptInvite(Message inviteMessage): called");
+
+ // Populate the test parameters from the invitation.
+ testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
+
+ for (Object key : testProps.keySet())
+ {
+ String propName = (String) key;
+
+ // If the test parameters is overridden by the invitation, use it instead.
+ String inviteValue = inviteMessage.getStringProperty(propName);
+
+ if (inviteValue != null)
+ {
+ testProps.setProperty(propName, inviteValue);
+ log.debug("Test invite supplied override to " + propName + " of " + inviteValue);
+ }
+
+ }
+
+ // Accept the invitation.
+ return true;
+ }
+
+ /**
+ * Assigns the role to be played by this test case. The test parameters are fully specified in the
+ * assignment message. When this method return the test case will be ready to execute.
+ *
+ * @param role The role to be played; sender or receivers.
+ * @param assignRoleMessage The role assingment message, contains the full test parameters.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ */
+ public void assignRole(Roles role, Message assignRoleMessage) throws JMSException
+ {
+ log.debug("public void assignRole(Roles role, Message assignRoleMessage): called");
+
+ // Take note of the role to be played.
+ this.role = role;
+
+ // Extract and retain the test parameters.
+ numMessages = 1; // assignRoleMessage.getIntProperty("NUM_MESSAGES");
+
+ // Connect using the test parameters.
+ connection = TestUtils.createConnection(testProps);
+
+ // Create a circuit end that matches the assigned role and test parameters.
+ switch (role)
+ {
+ // Check if the sender role is being assigned, and set up a message producer if so.
+ case SENDER:
+
+ // Set up the publisher.
+ circuitEnd = LocalCircuitImpl.createPublisherCircuitEnd(connection, testProps, 0L);
+
+ // Create a custom message monitor that will be updated on every message sent.
+ messageMonitor = new MessageMonitor();
+
+ break;
+
+ // Otherwise the receivers role is being assigned, so set this up to listen for messages.
+ case RECEIVER:
+
+ // Set up the receiver.
+ circuitEnd = LocalCircuitImpl.createReceiverCircuitEnd(connection, testProps, 0L);
+
+ // Use the message monitor from the consumer for stats.
+ messageMonitor = getMessageMonitor();
+
+ break;
+ }
+
+ // Reset all messaging stats for the report.
+ messageMonitor.reset();
+
+ connection.start();
+ }
+
+ /**
+ * Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
+ *
+ * @param numMessages The number of test messages to send.
+ *
+ * @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ *
+ * @todo Add round robin on destinations where multiple destinations being used.
+ *
+ * @todo Add rate limiting when rate limit specified on publishers.
+ *
+ * @todo Add Max pending message size protection. The receiver will have to send back some acks once in a while,
+ * to notify the publisher that its messages are being consumed. This makes the safety valve harder to
+ * implement than in the single VM case. For example, if the limit is 1000 messages, might want to get back
+ * an ack every 500, to notify the publisher that it can keep sending. What about pub/sub tests? Will it be
+ * necessary to wait for an ack from every receiver? This will have the effect of rate limiting to slow
+ * consumers too.
+ *
+ * @todo Add commits on every commit batch size boundary.
+ */
+ public void start(int numMessages) throws JMSException
+ {
+ log.debug("public void start(): called");
+
+ // If in the SENDER role, send the specified number of test messages to the circuit destinations.
+ if (role.equals(Roles.SENDER))
+ {
+ Message testMessage = getSession().createMessage();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ getProducer().send(testMessage);
+
+ // Increment the message count and timings.
+ messageMonitor.onMessage(testMessage);
+ }
+ }
+ }
+
+ /**
+ * Gets a report on the actions performed by the test case in its assigned role.
+ *
+ * @param session The controlSession to create the report message in.
+ * @return The report message.
+ *
+ * @throws JMSException Any JMSExceptions resulting from creating the report are allowed to fall through.
+ */
+ public Message getReport(Session session) throws JMSException
+ {
+ Message report = session.createMessage();
+ report.setStringProperty("CONTROL_TYPE", "REPORT");
+
+ // Add the count of messages sent/received to the report.
+ report.setIntProperty("MESSAGE_COUNT", messageMonitor.getNumMessage());
+
+ // Add the time to send/receive messages to the report.
+ report.setLongProperty("TEST_TIME", messageMonitor.getTime());
+
+ // Add any exceptions detected to the report.
+
+ return report;
+ }
+
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer()
+ {
+ return circuitEnd.getProducer();
+ }
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer()
+ {
+ return circuitEnd.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
+ {
+ // Send the message on the circuit ends producer.
+ circuitEnd.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 circuitEnd.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
+ {
+ // Close the producer and consumer.
+ circuitEnd.close();
+ }
+
+ /**
+ * Returns the message monitor for reporting on received messages on this circuit end.
+ *
+ * @return The message monitor for this circuit end.
+ */
+ public MessageMonitor getMessageMonitor()
+ {
+ return circuitEnd.getMessageMonitor();
+ }
+
+ /**
+ * Returns the exception monitor for reporting on exceptions received on this circuit end.
+ *
+ * @return The exception monitor for this circuit end.
+ */
+ public ExceptionMonitor getExceptionMonitor()
+ {
+ return circuitEnd.getExceptionMonitor();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java
index 7d28aee432..c4c9622091 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java
@@ -25,18 +25,23 @@ import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.apache.log4j.Logger;
+import org.apache.log4j.NDC;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.MessagingTestConfigProperties;
-import org.apache.qpid.test.framework.TestUtils;
import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.TestUtils;
import org.apache.qpid.test.framework.listeners.XMLTestListener;
import org.apache.qpid.util.ConversationFactory;
import org.apache.qpid.util.PrettyPrintingUtils;
+import uk.co.thebadgerset.junit.extensions.AsymptoticTestDecorator;
import uk.co.thebadgerset.junit.extensions.TKTestResult;
import uk.co.thebadgerset.junit.extensions.TKTestRunner;
import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
+import uk.co.thebadgerset.junit.extensions.listeners.CSVTestListener;
import uk.co.thebadgerset.junit.extensions.util.CommandLineParser;
+import uk.co.thebadgerset.junit.extensions.util.MathUtils;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
@@ -120,17 +125,43 @@ public class Coordinator extends TKTestRunner
/** Flag that indicates that all test clients should be terminated upon completion of the test cases. */
protected boolean terminate;
+ /** Flag that indicates the CSV results listener should be used to output results. */
+ protected boolean csvResults;
+
+ /** Flag that indiciates the XML results listener should be used to output results. */
+ protected boolean xmlResults;
+
/**
* Creates an interop test coordinator on the specified broker and virtual host.
*
- * @param brokerUrl The URL of the broker to connect to.
- * @param virtualHost The virtual host to run all tests on. Optional, may be <tt>null</tt>.
- * @param reportDir The directory to write out test results to.
- * @param engine The distributed test engine type to run the tests with.
+ * @param repetitions The number of times to repeat the test, or test batch size.
+ * @param duration The length of time to run the tests for. -1 means no duration has been set.
+ * @param threads The concurrency levels to ramp up to.
+ * @param delay A delay in milliseconds between test runs.
+ * @param params The sets of 'size' parameters to pass to test.
+ * @param testCaseName The name of the test case to run.
+ * @param reportDir The directory to output the test results to.
+ * @param runName The name of the test run; used to name the output file.
+ * @param verbose Whether to print comments during test run.
+ * @param brokerUrl The URL of the broker to connect to.
+ * @param virtualHost The virtual host to run all tests on. Optional, may be <tt>null</tt>.
+ * @param engine The distributed test engine type to run the tests with.
+ * @param terminate <tt>true</tt> if test client nodes should be terminated at the end of the tests.
+ * @param csv <tt>true</tt> if the CSV results listener should be attached.
+ * @param xml <tt>true</tt> if the XML results listener should be attached.
*/
- public Coordinator(String brokerUrl, String virtualHost, String reportDir, TestEngine engine, boolean terminate)
+ public Coordinator(Integer repetitions, Long duration, int[] threads, int delay, int[] params, String testCaseName,
+ String reportDir, String runName, boolean verbose, String brokerUrl, String virtualHost, TestEngine engine,
+ boolean terminate, boolean csv, boolean xml)
{
- log.debug("Coordinator(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost + "): called");
+ super(repetitions, duration, threads, delay, params, testCaseName, reportDir, runName, verbose);
+
+ log.debug("public Coordinator(Integer repetitions = " + repetitions + " , Long duration = " + duration
+ + ", int[] threads = " + Arrays.toString(threads) + ", int delay = " + delay + ", int[] params = "
+ + Arrays.toString(params) + ", String testCaseName = " + testCaseName + ", String reportDir = " + reportDir
+ + ", String runName = " + runName + ", boolean verbose = " + verbose + ", String brokerUrl = " + brokerUrl
+ + ", String virtualHost =" + virtualHost + ", TestEngine engine = " + engine + ", boolean terminate = "
+ + terminate + ", boolean csv = " + csv + ", boolean xml = " + xml + "): called");
// Retain the connection parameters.
this.brokerUrl = brokerUrl;
@@ -138,6 +169,8 @@ public class Coordinator extends TKTestRunner
this.reportDir = reportDir;
this.engine = engine;
this.terminate = terminate;
+ this.csvResults = csv;
+ this.xmlResults = xml;
}
/**
@@ -158,6 +191,8 @@ public class Coordinator extends TKTestRunner
*/
public static void main(String[] args)
{
+ NDC.push("coordinator");
+ log.debug("public static void main(String[] args = " + Arrays.toString(args) + "): called");
console.info("Qpid Distributed Test Coordinator.");
// Override the default broker url to be localhost:5672.
@@ -181,7 +216,25 @@ public class Coordinator extends TKTestRunner
"e", "The test execution engine to use. Default is interop.", "engine", "interop",
"^interop$|^fanout$", "true"
},
- { "t", "Terminate test clients on completion of tests.", "flag", "false" }
+ { "t", "Terminate test clients on completion of tests.", null, "false" },
+ { "-csv", "Output test results in CSV format.", null, "false" },
+ { "-xml", "Output test results in XML format.", null, "false" },
+ {
+ "c", "The number of tests to run concurrently.", "num", "false",
+ MathUtils.SEQUENCE_REGEXP
+ },
+ { "r", "The number of times to repeat each test.", "num", "false" },
+ {
+ "d", "The length of time to run the tests for.", "duration", "false",
+ MathUtils.DURATION_REGEXP
+ },
+ {
+ "f", "The maximum rate to call the tests at.", "frequency", "false",
+ "^([1-9][0-9]*)/([1-9][0-9]*)$"
+ },
+ { "s", "The size parameter to run tests with.", "size", "false", MathUtils.SEQUENCE_REGEXP },
+ { "v", "Verbose mode.", null, "false" },
+ { "n", "A name for this test run, used to name the output file.", "name", "true" }
}), testContextProperties));
// Extract the command line options.
@@ -192,16 +245,29 @@ public class Coordinator extends TKTestRunner
String testEngine = options.getProperty("e");
TestEngine engine = "fanout".equals(testEngine) ? TestEngine.FANOUT : TestEngine.INTEROP;
boolean terminate = options.getPropertyAsBoolean("t");
+ boolean csvResults = options.getPropertyAsBoolean("-csv");
+ boolean xmlResults = options.getPropertyAsBoolean("-xml");
+
+ String threadsString = options.getProperty("c");
+ Integer repetitions = options.getPropertyAsInteger("r");
+ String durationString = options.getProperty("d");
+ String paramsString = options.getProperty("s");
+ boolean verbose = options.getPropertyAsBoolean("v");
+ String testRunName = options.getProperty("n");
+
+ int[] threads = (threadsString == null) ? null : MathUtils.parseSequence(threadsString);
+ int[] params = (paramsString == null) ? null : MathUtils.parseSequence(paramsString);
+ Long duration = (durationString == null) ? null : MathUtils.parseDuration(durationString);
// If broker or virtual host settings were specified as command line options, override the defaults in the
// test context properties with them.
// Collection all of the test cases to be run.
- Collection<Class<? extends DistributedTestCase>> testCaseClasses =
- new ArrayList<Class<? extends DistributedTestCase>>();
+ Collection<Class<? extends FrameworkBaseCase>> testCaseClasses =
+ new ArrayList<Class<? extends FrameworkBaseCase>>();
// Scan for available test cases using a classpath scanner.
- // ClasspathScanner.getMatches(InteropTestCase.class, "^Test.*", true);
+ // ClasspathScanner.getMatches(DistributedTestCase.class, "^Test.*", true);
// Hard code the test classes till the classpath scanner is fixed.
// Collections.addAll(testCaseClasses, InteropTestCase1DummyRun.class, InteropTestCase2BasicP2P.class,
@@ -222,7 +288,7 @@ public class Coordinator extends TKTestRunner
{
Class nextClass = Class.forName(nextFreeArg);
- if (DistributedTestCase.class.isAssignableFrom(nextClass))
+ if (FrameworkBaseCase.class.isAssignableFrom(nextClass))
{
testCaseClasses.add(nextClass);
console.info("Found distributed test case: " + nextFreeArg);
@@ -237,7 +303,8 @@ public class Coordinator extends TKTestRunner
// Check that some test classes were actually found.
if (testCaseClasses.isEmpty())
{
- throw new RuntimeException("No test cases implementing InteropTestCase were specified on the command line.");
+ throw new RuntimeException(
+ "No test cases implementing DistributedTestCase were specified on the command line.");
}
// Extract the names of all the test classes, to pass to the start method.
@@ -250,7 +317,9 @@ public class Coordinator extends TKTestRunner
}
// Create a coordinator and begin its test procedure.
- Coordinator coordinator = new Coordinator(brokerUrl, virtualHost, reportDir, engine, terminate);
+ Coordinator coordinator =
+ new Coordinator(repetitions, duration, threads, 0, params, null, reportDir, testRunName, verbose, brokerUrl,
+ virtualHost, engine, terminate, csvResults, xmlResults);
TestResult testResult = coordinator.start(testClassNames);
@@ -306,10 +375,15 @@ public class Coordinator extends TKTestRunner
conversation.send(controlTopic, invite);
// Wait for a short time, to give test clients an opportunity to reply to the invitation.
- Collection<Message> enlists = conversation.receiveAll(0, 3000);
-
+ Collection<Message> enlists = conversation.receiveAll(0, 500);
enlistedClients = extractEnlists(enlists);
+ for (TestClientDetails client : enlistedClients)
+ {
+ log.debug("Got enlisted test client: " + client);
+ console.info("Test node " + client.clientName + " available.");
+ }
+
// Run the test in the suite using JUnit.
TestResult result = null;
@@ -357,7 +431,20 @@ public class Coordinator extends TKTestRunner
clientDetails.clientName = enlist.getStringProperty("CLIENT_NAME");
clientDetails.privateControlKey = enlist.getStringProperty("CLIENT_PRIVATE_CONTROL_KEY");
- enlistedClients.add(clientDetails);
+ String replyType = enlist.getStringProperty("CONTROL_TYPE");
+
+ if ("ENLIST".equals(replyType))
+ {
+ enlistedClients.add(clientDetails);
+ }
+ else if ("DECLINE".equals(replyType))
+ {
+ log.debug("Test client " + clientDetails.clientName + " declined the invite.");
+ }
+ else
+ {
+ log.warn("Got an unknown reply type, " + replyType + ", to the invite.");
+ }
}
return enlistedClients;
@@ -395,9 +482,9 @@ public class Coordinator extends TKTestRunner
Test nextTest = suite.testAt(i);
log.debug("suite.testAt(" + i + ") = " + nextTest);
- if (nextTest instanceof DistributedTestCase)
+ if (nextTest instanceof FrameworkBaseCase)
{
- log.debug("nextTest is a DistributedTestCase");
+ log.debug("nextTest is a FrameworkBaseCase");
}
}
@@ -408,13 +495,13 @@ public class Coordinator extends TKTestRunner
// Wrap the tests in a suitable distributed test decorator, to perform the invite/test cycle.
targetTest = newTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
- TestSuite suite = new TestSuite();
- suite.addTest(targetTest);
+ // TestSuite suite = new TestSuite();
+ // suite.addTest(targetTest);
// Wrap the tests in a scaled test decorator to them them as a 'batch' in one thread.
// targetTest = new ScaledTestDecorator(targetTest, new int[] { 1 });
- return super.doRun(suite, wait);
+ return super.doRun(targetTest, wait);
}
/**
@@ -466,20 +553,48 @@ public class Coordinator extends TKTestRunner
// Create the results file (make the name of this configurable as a command line parameter).
Writer timingsWriter;
- try
+ // Set up an XML results listener to output the timings to the results file, if requested on the command line.
+ if (xmlResults)
{
- File timingsFile = new File(reportDirFile, "TEST." + currentTestClassName + ".xml");
- timingsWriter = new BufferedWriter(new FileWriter(timingsFile), 20000);
+ try
+ {
+ File timingsFile = new File(reportDirFile, "TEST." + currentTestClassName + ".xml");
+ timingsWriter = new BufferedWriter(new FileWriter(timingsFile), 20000);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to create the log file to write test results to: " + e, e);
+ }
+
+ XMLTestListener listener = new XMLTestListener(timingsWriter, currentTestClassName);
+ result.addListener(listener);
+ result.addTKTestListener(listener);
+
+ registerShutdownHook(listener);
}
- catch (IOException e)
+
+ // Set up an CSV results listener to output the timings to the results file, if requested on the command line.
+ if (csvResults)
{
- throw new RuntimeException("Unable to create the log file to write test results to: " + e, e);
- }
+ try
+ {
+ File timingsFile =
+ new File(reportDirFile, testRunName + "-" + TIME_STAMP_FORMAT.format(new Date()) + "-timings.csv");
+ timingsWriter = new BufferedWriter(new FileWriter(timingsFile), 20000);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to create the log file to write test results to: " + e, e);
+ }
- // Set up an XML results listener to output the timings to the results file.
- XMLTestListener listener = new XMLTestListener(timingsWriter, currentTestClassName);
- result.addListener(listener);
- result.addTKTestListener(listener);
+ CSVTestListener listener = new CSVTestListener(timingsWriter);
+ result.addListener(listener);
+ result.addTKTestListener(listener);
+
+ // Register the results listeners shutdown hook to flush its data if the test framework is shutdown
+ // prematurely.
+ registerShutdownHook(listener);
+ }
// Register the results listeners shutdown hook to flush its data if the test framework is shutdown
// prematurely.
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java
deleted file mode 100644
index c47650ba1c..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java
+++ /dev/null
@@ -1,81 +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.test.framework.distributedtesting;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
-import org.apache.qpid.test.framework.FrameworkBaseCase;
-
-/**
- * DistributedTestCase provides a base class implementation of the {@link org.apache.qpid.test.framework.sequencers.DistributedTestSequencer}, taking care of its
- * more mundane aspects, such as recording the test pariticipants.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Accept notification of test case participants.
- * <td> {@link DistributedTestDecorator}
- * <tr><td> Accept JMS Connection to carry out the coordination over.
- * </table>
- */
-public abstract class DistributedTestCase extends FrameworkBaseCase
-{
- /** Used for debugging. */
- private final Logger log = Logger.getLogger(DistributedTestCase.class);
-
- /**
- * Creates a new test case with the specified name.
- *
- * @param name The test case name.
- */
- public DistributedTestCase(String name)
- {
- super(name);
- }
-
- /**
- * Gets the test sequencer for this distributed test, cast as a {@link DistributedTestSequencer}, provided that it
- * is one. If the test sequencer is not distributed, this returns null.
- */
- public DistributedTestSequencer getDistributedTestSequencer()
- {
- try
- {
- return (DistributedTestSequencer) testSequencer;
- }
- catch (ClassCastException e)
- {
- return null;
- }
- }
-
- /**
- * Should provide a translation from the junit method name of a test to its test case name as known to the test
- * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
- * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
- * name "TC2_BasicP2P".
- *
- * @param methodName The name of the JUnit test method.
- *
- * @return The name of the corresponding interop test case.
- */
- public abstract String getTestCaseNameForTestMethod(String methodName);
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java
index bcc409dff9..c2f34b44fc 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java
@@ -24,8 +24,9 @@ import junit.framework.TestResult;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
@@ -42,10 +43,9 @@ import java.util.*;
* distributed test cases. It provides a helper method, {@link #signupClients}, that broadcasts an invitation and
* returns the set of test clients that are available to particiapte in the test.
*
- * <p/>When used to wrap a {@link org.apache.qpid.test.framework.FrameworkBaseCase} test, it replaces the default
- * {@link org.apache.qpid.test.framework.sequencers.TestCaseSequencer} implementations with a suitable
- * {@link org.apache.qpid.test.framework.sequencers.DistributedTestSequencer}. Concrete implementations
- * can use this to configure the sending and receiving roles on the test.
+ * <p/>When used to wrap a {@link FrameworkBaseCase} test, it replaces the default {@link CircuitFactory} implementations
+ * with a suitable circuit factory for distributed tests. Concrete implementations can use this to configure the sending
+ * and receiving roles on the test.
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
@@ -66,7 +66,7 @@ public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
/** Holds the connection that the control conversation is held over. */
Connection connection;
- /** Holds the underlying {@link DistributedTestCase}s that this decorator wraps. */
+ /** Holds the underlying test suite that this decorator wraps. */
WrappedSuiteTestDecorator testSuite;
/** Holds the control topic, on which test invitations are broadcast. */
@@ -117,7 +117,7 @@ public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
*
* @return A distributed test sequencer.
*/
- public abstract DistributedTestSequencer getDistributedTestSequencer();
+ public abstract CircuitFactory getTestSequencer();
/**
* Broadcasts an invitation to participate in a coordinating test case to find out what clients are available to
@@ -127,7 +127,7 @@ public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
*
* @return A set of test clients that accepted the invitation.
*/
- protected Set<TestClientDetails> signupClients(DistributedTestCase coordTest)
+ protected Set<TestClientDetails> signupClients(FrameworkBaseCase coordTest)
{
// Broadcast the invitation to find out what clients are available to test.
Set<TestClientDetails> enlists;
@@ -143,7 +143,7 @@ public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
conversation.send(controlTopic, invite);
// Wait for a short time, to give test clients an opportunity to reply to the invitation.
- Collection<Message> replies = conversation.receiveAll(allClients.size(), 3000);
+ Collection<Message> replies = conversation.receiveAll(allClients.size(), 500);
enlists = Coordinator.extractEnlists(replies);
}
catch (JMSException e)
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java
index 83d6602e57..eed24c65c1 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java
@@ -25,11 +25,12 @@ import junit.framework.TestResult;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
-import org.apache.qpid.test.framework.sequencers.FanOutTestSequencer;
import org.apache.qpid.test.framework.DropInTest;
-import org.apache.qpid.util.ConversationFactory;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
+import org.apache.qpid.test.framework.sequencers.FanOutCircuitFactory;
+import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
@@ -50,7 +51,7 @@ import java.util.Set;
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Execute coordinated test cases. <td> {@link DistributedTestCase}
+ * <tr><td> Execute coordinated test cases. <td> {@link FrameworkBaseCase}
* <tr><td> Accept test clients joining a running test.
* </table>
*/
@@ -60,7 +61,7 @@ public class FanOutTestDecorator extends DistributedTestDecorator implements Mes
private static final Logger log = Logger.getLogger(FanOutTestDecorator.class);
/** Holds the currently running test case. */
- DistributedTestCase currentTest = null;
+ FrameworkBaseCase currentTest = null;
/**
* Creates a wrapped suite test decorator from another one.
@@ -112,9 +113,9 @@ public class FanOutTestDecorator extends DistributedTestDecorator implements Mes
}
// Run all of the test cases in the test suite.
- for (Test test : tests)
+ for (Test test : getAllUnderlyingTests())
{
- DistributedTestCase coordTest = (DistributedTestCase) test;
+ FrameworkBaseCase coordTest = (FrameworkBaseCase) test;
// Get all of the clients able to participate in the test.
Set<TestClientDetails> enlists = signupClients(coordTest);
@@ -125,28 +126,28 @@ public class FanOutTestDecorator extends DistributedTestDecorator implements Mes
throw new RuntimeException("No clients to test with");
}
- // Create a distributed test sequencer for the test.
- DistributedTestSequencer sequencer = getDistributedTestSequencer();
+ // Create a distributed test circuit factory for the test.
+ CircuitFactory circuitFactory = getTestSequencer();
// Set up the first client in the sender role, and the remainder in the receivers role.
Iterator<TestClientDetails> clients = enlists.iterator();
- sequencer.setSender(clients.next());
+ circuitFactory.setSender(clients.next());
while (clients.hasNext())
{
// Set the sending and receiving client details on the test case.
- sequencer.setReceiver(clients.next());
+ circuitFactory.setReceiver(clients.next());
}
// Pass down the connection to hold the coordinating conversation over.
- sequencer.setConversationFactory(conversationFactory);
+ circuitFactory.setConversationFactory(conversationFactory);
// If the current test case is a drop-in test, set it up as the currently running test for late joiners to
// add in to. Otherwise the current test field is set to null, to indicate that late joiners are not allowed.
currentTest = (coordTest instanceof DropInTest) ? coordTest : null;
// Execute the test case.
- coordTest.setTestSequencer(sequencer);
+ coordTest.setCircuitFactory(circuitFactory);
coordTest.run(testResult);
currentTest = null;
@@ -159,9 +160,9 @@ public class FanOutTestDecorator extends DistributedTestDecorator implements Mes
*
* @return A distributed test sequencer.
*/
- public DistributedTestSequencer getDistributedTestSequencer()
+ public CircuitFactory getTestSequencer()
{
- return new FanOutTestSequencer();
+ return new FanOutCircuitFactory();
}
/**
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java
index 7743d2bba3..918f0f9177 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java
@@ -25,9 +25,10 @@ import junit.framework.TestResult;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
-import org.apache.qpid.test.framework.sequencers.InteropTestSequencer;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
+import org.apache.qpid.test.framework.sequencers.InteropCircuitFactory;
import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
@@ -48,7 +49,7 @@ import java.util.*;
* <tr><th> Responsibilities <th> Collaborations
* <tr><td> Broadcast test invitations and collect enlists. <td> {@link org.apache.qpid.util.ConversationFactory}.
* <tr><td> Output test failures for clients unwilling to run the test case. <td> {@link Coordinator}
- * <tr><td> Execute distributed test cases. <td> {@link DistributedTestCase}
+ * <tr><td> Execute distributed test cases. <td> {@link FrameworkBaseCase}
* <tr><td> Fail non participating pairings. <td> {@link OptOutTestCase}
* </table>
*/
@@ -74,7 +75,7 @@ public class InteropTestDecorator extends DistributedTestDecorator
/**
* Broadcasts a test invitation and accetps enlisting from participating clients. The wrapped test case is
* then repeated for every combination of test clients (provided the wrapped test case extends
- * {@link DistributedTestCase}.
+ * {@link FrameworkBaseCase}.
*
* <p/>Any JMSExceptions during the invite/enlist conversation will be allowed to fall through as runtime exceptions,
* resulting in the non-completion of the test run.
@@ -89,9 +90,9 @@ public class InteropTestDecorator extends DistributedTestDecorator
Collection<Test> tests = testSuite.getAllUnderlyingTests();
- for (Test test : tests)
+ for (Test test : getAllUnderlyingTests())
{
- DistributedTestCase coordTest = (DistributedTestCase) test;
+ FrameworkBaseCase coordTest = (FrameworkBaseCase) test;
// Broadcast the invitation to find out what clients are available to test.
Set<TestClientDetails> enlists = signupClients(coordTest);
@@ -105,14 +106,14 @@ public class InteropTestDecorator extends DistributedTestDecorator
for (List<TestClientDetails> failPair : failPairs)
{
- // Create a distributed test sequencer for the test.
- DistributedTestSequencer sequencer = getDistributedTestSequencer();
+ // Create a distributed test circuit factory for the test.
+ CircuitFactory circuitFactory = getTestSequencer();
// Create an automatic failure test for the opted out test pair.
- DistributedTestCase failTest = new OptOutTestCase("testOptOut");
- sequencer.setSender(failPair.get(0));
- sequencer.setReceiver(failPair.get(1));
- failTest.setTestSequencer(sequencer);
+ FrameworkBaseCase failTest = new OptOutTestCase("testOptOut");
+ circuitFactory.setSender(failPair.get(0));
+ circuitFactory.setReceiver(failPair.get(1));
+ failTest.setCircuitFactory(circuitFactory);
failTest.run(testResult);
}
@@ -122,18 +123,18 @@ public class InteropTestDecorator extends DistributedTestDecorator
for (List<TestClientDetails> enlistedPair : enlistedPairs)
{
- // Create a distributed test sequencer for the test.
- DistributedTestSequencer sequencer = getDistributedTestSequencer();
+ // Create a distributed test circuit factory for the test.
+ CircuitFactory circuitFactory = getTestSequencer();
- // Set the sending and receiving client details on the test sequencer.
- sequencer.setSender(enlistedPair.get(0));
- sequencer.setReceiver(enlistedPair.get(1));
+ // Set the sending and receiving client details on the test circuitFactory.
+ circuitFactory.setSender(enlistedPair.get(0));
+ circuitFactory.setReceiver(enlistedPair.get(1));
// Pass down the connection to hold the coordination conversation over.
- sequencer.setConversationFactory(conversationFactory);
+ circuitFactory.setConversationFactory(conversationFactory);
// Execute the test case.
- coordTest.setTestSequencer(sequencer);
+ coordTest.setCircuitFactory(circuitFactory);
coordTest.run(testResult);
}
}
@@ -145,9 +146,9 @@ public class InteropTestDecorator extends DistributedTestDecorator
*
* @return A distributed test sequencer.
*/
- public DistributedTestSequencer getDistributedTestSequencer()
+ public CircuitFactory getTestSequencer()
{
- return new InteropTestSequencer();
+ return new InteropCircuitFactory();
}
/**
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java
index 83ec12ad56..fcdac20ca2 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java
@@ -20,7 +20,8 @@
*/
package org.apache.qpid.test.framework.distributedtesting;
-import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.sequencers.CircuitFactory;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
/**
* An OptOutTestCase is a test case that automatically fails. It is used when a list of test clients has been generated
@@ -32,7 +33,7 @@ import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
* <tr><td> Fail the test with a suitable reason.
* </table>
*/
-public class OptOutTestCase extends DistributedTestCase
+public class OptOutTestCase extends FrameworkBaseCase
{
/**
* Creates a new coordinating test case with the specified name.
@@ -47,9 +48,9 @@ public class OptOutTestCase extends DistributedTestCase
/** Generates an appropriate test failure assertion. */
public void testOptOut()
{
- DistributedTestSequencer sequencer = getDistributedTestSequencer();
+ CircuitFactory circuitFactory = getCircuitFactory();
- fail("One of " + sequencer.getSender() + " and " + getDistributedTestSequencer().getReceivers()
+ fail("One of " + circuitFactory.getSender() + " and " + getCircuitFactory().getReceivers()
+ " opted out of the test.");
}
diff --git a/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropClientTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClientControlledTest.java
index 5e6d61a9e0..893a022b97 100644
--- a/java/integrationtests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropClientTestCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/TestClientControlledTest.java
@@ -26,9 +26,14 @@ import javax.jms.MessageListener;
import javax.jms.Session;
/**
- * InteropClientTestCase provides an interface that classes implementing test cases from the interop testing spec
- * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification) should implement. Implementations
- * must be Java beans, that is, to provide a default constructor and to implement the {@link #getName} method.
+ * TestClientControlledTest provides an interface that classes implementing test cases to run on a {@link TestClient}
+ * node can use. Implementations must be Java beans, that is, to provide a default constructor and to implement the
+ * {@link #getName} method.
+ *
+ * <p/>The methods specified in this interface are called when the {@link TestClient} receives control instructions to
+ * apply to the test. There are control instructions to present the test case with the test invite, so that it may
+ * choose whether or not to participate in the test, assign the test to play the sender or receiver role, start the
+ * test and obtain the test status report.
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities
@@ -39,7 +44,7 @@ import javax.jms.Session;
* <tr><td> Generate test reports.
* </table>
*/
-public interface InteropClientTestCase extends MessageListener
+public interface TestClientControlledTest
{
/** Defines the possible test case roles that an interop test case can take on. */
public enum Roles
@@ -84,14 +89,16 @@ public interface InteropClientTestCase extends MessageListener
/**
* Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
*
+ * @param numMessages The number of test messages to send.
+ *
* @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
*/
- public void start() throws JMSException;
+ public void start(int numMessages) throws JMSException;
/**
* Gets a report on the actions performed by the test case in its assigned role.
*
- * @param session The session to create the report message in.
+ * @param session The controlSession to create the report message in.
*
* @return The report message.
*
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java b/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java
index ee274a1e01..014dd21292 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java
@@ -26,6 +26,7 @@ import junit.framework.TestCase;
import org.apache.log4j.Logger;
+import uk.co.thebadgerset.junit.extensions.ShutdownHookable;
import uk.co.thebadgerset.junit.extensions.listeners.TKTestListener;
import java.io.IOException;
@@ -62,7 +63,7 @@ import java.util.*;
* the ant XML formatter, and a more structured one for outputing results with timings and summaries from
* performance tests.
*/
-public class XMLTestListener implements TKTestListener
+public class XMLTestListener implements TKTestListener, ShutdownHookable
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(XMLTestListener.class);
@@ -351,6 +352,22 @@ public class XMLTestListener implements TKTestListener
}
/**
+ * Supplies the shutdown hook.
+ *
+ * @return The shut down hook.
+ */
+ public Thread getShutdownHook()
+ {
+ return new Thread(new Runnable()
+ {
+ public void run()
+ {
+ log.debug("XMLTestListener::ShutdownHook: called");
+ }
+ });
+ }
+
+ /**
* Used to capture the results of a particular test run.
*/
protected static class Result
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalCircuitImpl.java
index 3c678eef7d..ff7330f483 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalCircuitImpl.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.test.framework.localcircuit;
+import org.apache.log4j.Logger;
+
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.test.framework.*;
@@ -32,27 +34,27 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/**
- * CircuitImpl provides an implementation of the test circuit. This is a first prototype implementation and only supports
- * a single producer/consumer on each end of the circuit, with both ends of the circuit on the same JVM.
+ * LocalCircuitImpl provides an implementation of the test circuit. This is a local only circuit implementation that
+ * supports a single producer/consumer on each end of the circuit, with both ends of the circuit on the same JVM.
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
- * <td> {@link PublisherImpl}, {@link ReceiverImpl}
+ * <td> {@link LocalPublisherImpl}, {@link LocalReceiverImpl}
* <tr><td> Start the circuit running.
* <tr><td> Close the circuit down.
* <tr><td> Take a reading of the circuits state.
- * <tr><td> Apply assertions against the circuits state. <td> {@link org.apache.qpid.test.framework.Assertion}
+ * <tr><td> Apply assertions against the circuits state. <td> {@link Assertion}
* <tr><td> Send test messages over the circuit.
* <tr><td> Perform the default test procedure on the circuit.
- * <tr><td> Provide access to connection and session exception monitors <td> {@link org.apache.qpid.test.framework.ExceptionMonitor}
+ * <tr><td> Provide access to connection and controlSession exception monitors <td> {@link ExceptionMonitor}
* </table>
- *
- * @todo Add ability to create routes with no consumers active on them. Immediate/Mandatory tests are closing consumers
- * themsleves to create this scenario. Should make it part of the test configuration.
*/
-public class CircuitImpl implements Circuit
+public class LocalCircuitImpl implements Circuit
{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(LocalCircuitImpl.class);
+
/** Used to create unique destination names for each test. */
private static AtomicLong uniqueDestsId = new AtomicLong();
@@ -60,10 +62,10 @@ public class CircuitImpl implements Circuit
private ParsedProperties testProps;
/** Holds the publishing end of the circuit. */
- private PublisherImpl publisher;
+ private LocalPublisherImpl publisher;
/** Holds the receiving end of the circuit. */
- private ReceiverImpl receiver;
+ private LocalReceiverImpl receiver;
/** Holds the connection for the publishing end of the circuit. */
private Connection connection;
@@ -71,7 +73,7 @@ public class CircuitImpl implements Circuit
/** 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. */
+ /** Holds the exception listener for the controlSession on the publishing end of the circuit. */
private ExceptionMonitor exceptionMonitor;
/**
@@ -84,8 +86,8 @@ public class CircuitImpl implements Circuit
* @param connection The connection.
* @param connectionExceptionMonitor The connection exception monitor.
*/
- protected CircuitImpl(ParsedProperties testProps, PublisherImpl publisher, ReceiverImpl receiver, Connection connection,
- ExceptionMonitor connectionExceptionMonitor)
+ protected LocalCircuitImpl(ParsedProperties testProps, LocalPublisherImpl publisher, LocalReceiverImpl receiver,
+ Connection connection, ExceptionMonitor connectionExceptionMonitor)
{
this.testProps = testProps;
this.publisher = publisher;
@@ -100,7 +102,7 @@ public class CircuitImpl implements Circuit
}
/**
- * Creates a test circuit from the specified test parameters.
+ * Creates a local test circuit from the specified test parameters.
*
* @param testProps The test parameters.
*
@@ -111,111 +113,145 @@ public class CircuitImpl implements Circuit
// Create a standard publisher/receivers test client pair on a shared connection, individual sessions.
try
{
- // ParsedProperties testProps = new ParsedProperties(testProps);
+ // Cast the test properties into a typed interface for convenience.
+ MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);
// 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.
+ // Set up the connection.
Connection connection = TestUtils.createConnection(testProps);
// Add the connection exception listener to assert on exception conditions with.
- ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
- connection.setExceptionListener(exceptionMonitor);
+ // ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
+ // connection.setExceptionListener(exceptionMonitor);
- Session publisherSession = connection.createSession(transactional, ackMode);
- Session receiverSession = connection.createSession(transactional, ackMode);
+ // Set up the publisher.
+ CircuitEndBase publisherEnd = createPublisherCircuitEnd(connection, props, uniqueId);
- Destination publisherProducerDestination =
- useTopics ? publisherSession.createTopic(destinationSendRoot)
- : publisherSession.createQueue(destinationSendRoot);
+ // Set up the receiver.
+ CircuitEndBase receiverEnd = createReceiverCircuitEnd(connection, props, uniqueId);
- MessageProducer publisherProducer =
- createPublisherProducer
- ? (needsQpidOptions
- ? ((AMQSession) publisherSession).createProducer(publisherProducerDestination, mandatory, immediate)
- : publisherSession.createProducer(publisherProducerDestination)) : null;
+ // Start listening for incoming messages.
+ connection.start();
- MessageConsumer publisherConsumer =
- createPublisherConsumer
- ? publisherSession.createConsumer(publisherSession.createQueue(destinationReceiveRoot)) : null;
+ // Package everything up.
+ LocalPublisherImpl publisher = new LocalPublisherImpl(publisherEnd);
+ LocalReceiverImpl receiver = new LocalReceiverImpl(receiverEnd);
- if (publisherConsumer != null)
- {
- publisherConsumer.setMessageListener(new MessageMonitor());
- }
+ return new LocalCircuitImpl(testProps, publisher, receiver, connection, publisher.getExceptionMonitor());
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Could not create publisher/receivers pair due to a JMSException.", e);
+ }
+ }
+
+ /**
+ * Builds a circuit end suitable for the publishing side of a test circuit, from standard test parameters.
+ *
+ * @param connection The connection to build the circuit end on.
+ * @param testProps The test parameters to configure the circuit end construction.
+ * @param uniqueId A unique number to being numbering destinations from, to make this circuit unique.
+ *
+ * @return A circuit end suitable for the publishing side of a test circuit.
+ *
+ * @throws JMSException Any underlying JMSExceptions are allowed to fall through and fail the creation.
+ */
+ public static CircuitEndBase createPublisherCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId)
+ throws JMSException
+ {
+ log.debug(
+ "public static CircuitEndBase createPublisherCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId = "
+ + uniqueId + "): called");
- MessageProducer receiverProducer =
- createReceiverProducer ? receiverSession.createProducer(receiverSession.createQueue(destinationReceiveRoot))
- : null;
+ // Cast the test properties into a typed interface for convenience.
+ MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);
- Destination receiverConsumerDestination =
- useTopics ? receiverSession.createTopic(destinationSendRoot)
- : receiverSession.createQueue(destinationSendRoot);
+ Session session = connection.createSession(props.getTransacted(), props.getAckMode());
- MessageConsumer receiverConsumer =
- createReceiverConsumer
- ? ((durableSubscription && useTopics)
- ? receiverSession.createDurableSubscriber((Topic) receiverConsumerDestination, "testsub")
- : receiverSession.createConsumer(receiverConsumerDestination)) : null;
+ Destination destination =
+ props.getPubsub() ? session.createTopic(props.getSendDestinationNameRoot() + "_" + uniqueId)
+ : session.createQueue(props.getSendDestinationNameRoot() + "_" + uniqueId);
- if (receiverConsumer != null)
- {
- receiverConsumer.setMessageListener(new MessageMonitor());
- }
+ MessageProducer producer =
+ props.getPublisherProducerBind()
+ ? ((props.getImmediate() | props.getMandatory())
+ ? ((AMQSession) session).createProducer(destination, props.getMandatory(), props.getImmediate())
+ : session.createProducer(destination)) : null;
- // Start listening for incoming messages.
- connection.start();
+ MessageConsumer consumer =
+ props.getPublisherConsumerBind()
+ ? session.createConsumer(session.createQueue(props.getReceiveDestinationNameRoot() + "_" + uniqueId)) : null;
- // Package everything up.
- PublisherImpl publisher = new PublisherImpl(publisherProducer, publisherConsumer, publisherSession);
- ReceiverImpl receiver = new ReceiverImpl(receiverProducer, receiverConsumer, receiverSession);
+ MessageMonitor messageMonitor = new MessageMonitor();
- return new CircuitImpl(testProps, publisher, receiver, connection, exceptionMonitor);
+ if (consumer != null)
+ {
+ consumer.setMessageListener(messageMonitor);
}
- catch (JMSException e)
+
+ ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
+ connection.setExceptionListener(exceptionMonitor);
+
+ if (!props.getPublisherConsumerActive() && (consumer != null))
{
- throw new RuntimeException("Could not create publisher/receivers pair due to a JMSException.", e);
+ consumer.close();
+ }
+
+ return new CircuitEndBase(producer, consumer, session, messageMonitor, exceptionMonitor);
+ }
+
+ /**
+ * Builds a circuit end suitable for the receiving side of a test circuit, from standard test parameters.
+ *
+ * @param connection The connection to build the circuit end on.
+ * @param testProps The test parameters to configure the circuit end construction.
+ * @param uniqueId A unique number to being numbering destinations from, to make this circuit unique.
+ *
+ * @return A circuit end suitable for the receiving side of a test circuit.
+ *
+ * @throws JMSException Any underlying JMSExceptions are allowed to fall through and fail the creation.
+ */
+ public static CircuitEndBase createReceiverCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId)
+ throws JMSException
+ {
+ log.debug(
+ "public static CircuitEndBase createReceiverCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId = "
+ + uniqueId + "): called");
+
+ // Cast the test properties into a typed interface for convenience.
+ MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);
+
+ Session session = connection.createSession(props.getTransacted(), props.getAckMode());
+
+ MessageProducer producer =
+ props.getReceiverProducerBind()
+ ? session.createProducer(session.createQueue(props.getReceiveDestinationNameRoot() + "_" + uniqueId)) : null;
+
+ Destination destination =
+ props.getPubsub() ? session.createTopic(props.getSendDestinationNameRoot() + "_" + uniqueId)
+ : session.createQueue(props.getSendDestinationNameRoot() + "_" + uniqueId);
+
+ MessageConsumer consumer =
+ props.getReceiverConsumerBind()
+ ? ((props.getDurableSubscription() && props.getPubsub())
+ ? session.createDurableSubscriber((Topic) destination, "testsub") : session.createConsumer(destination))
+ : null;
+
+ MessageMonitor messageMonitor = new MessageMonitor();
+
+ if (consumer != null)
+ {
+ consumer.setMessageListener(messageMonitor);
+ }
+
+ if (!props.getReceiverConsumerActive() && (consumer != null))
+ {
+ consumer.close();
}
+
+ return new CircuitEndBase(producer, consumer, session, messageMonitor, null);
}
/**
@@ -229,6 +265,16 @@ public class CircuitImpl implements Circuit
}
/**
+ * Gets the local publishing circuit end, for direct manipulation.
+ *
+ * @return The local publishing circuit end.
+ */
+ public CircuitEnd getLocalPublisherCircuitEnd()
+ {
+ return publisher;
+ }
+
+ /**
* Gets the interface on the receiving end of the circuit.
*
* @return The receiving end of the circuit.
@@ -239,6 +285,16 @@ public class CircuitImpl implements Circuit
}
/**
+ * Gets the local receiving circuit end, for direct manipulation.
+ *
+ * @return The local receiving circuit end.
+ */
+ public CircuitEnd getLocalReceiverCircuitEnd()
+ {
+ 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.
*/
@@ -293,18 +349,20 @@ public class CircuitImpl implements Circuit
/**
* Sends a message on the test circuit. The exact nature of the message sent is controlled by the test parameters.
*/
- public void send()
+ protected 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()));
+ CircuitEnd end = getLocalPublisherCircuitEnd();
+
+ end.send(createTestMessage(end));
if (transactional)
{
- getPublisher().getSession().commit();
+ end.getSession().commit();
}
}
catch (JMSException e)
@@ -351,7 +409,7 @@ public class CircuitImpl implements Circuit
// Apply all of the requested assertions, keeping record of any that fail.
List<Assertion> failures = applyAssertions(assertions);
- // Clean up the publisher/receivers/session/connections.
+ // Clean up the publisher/receivers/controlSession/connections.
close();
// Return any failed assertions to the caller.
@@ -383,9 +441,9 @@ public class CircuitImpl implements Circuit
}
/**
- * Gets the exception monitor for the publishing ends session.
+ * Gets the exception monitor for the publishing ends controlSession.
*
- * @return The exception monitor for the publishing ends session.
+ * @return The exception monitor for the publishing ends controlSession.
*/
public ExceptionMonitor getExceptionMonitor()
{
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalPublisherImpl.java
index 5b63607867..93a137dffa 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalPublisherImpl.java
@@ -22,7 +22,6 @@ package org.apache.qpid.test.framework.localcircuit;
import org.apache.qpid.client.AMQNoConsumersException;
import org.apache.qpid.client.AMQNoRouteException;
-import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
import org.apache.qpid.test.framework.*;
import javax.jms.MessageConsumer;
@@ -30,8 +29,10 @@ import javax.jms.MessageProducer;
import javax.jms.Session;
/**
- * Provides an implementation of the {@link org.apache.qpid.test.framework.Publisher} interface that wraps a single message producer and consumer on
- * a single session.
+ * Provides an implementation of the {@link Publisher} interface and wraps a single message producer and consumer on
+ * a single controlSession, as a {@link CircuitEnd}. A local publisher also acts as a circuit end, because for a locally
+ * located circuit the assertions may be applied directly, there does not need to be any inter process messaging
+ * between the publisher and its single circuit end, in order to ascertain its status.
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
@@ -42,21 +43,32 @@ import javax.jms.Session;
* <tr><td> Provide assertion that the publisher received a no route error code.
* </table>
*/
-public class PublisherImpl extends CircuitEndBase implements Publisher
+public class LocalPublisherImpl extends CircuitEndBase implements Publisher
{
/** Holds a reference to the containing circuit. */
- private CircuitImpl circuit;
+ private LocalCircuitImpl circuit;
/**
- * Creates a circuit end point on the specified producer, consumer and session.
+ * Creates a circuit end point on the specified producer, consumer and controlSession.
*
* @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.
+ * @param session The controlSession for the circuit end point.
*/
- public PublisherImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ public LocalPublisherImpl(MessageProducer producer, MessageConsumer consumer, Session session,
+ MessageMonitor messageMonitor, ExceptionMonitor exceptionMonitor)
{
- super(producer, consumer, session);
+ super(producer, consumer, session, messageMonitor, exceptionMonitor);
+ }
+
+ /**
+ * Creates a circuit end point from the producer, consumer and controlSession in a circuit end base implementation.
+ *
+ * @param end The circuit end base implementation to take producers and consumers from.
+ */
+ public LocalPublisherImpl(CircuitEndBase end)
+ {
+ super(end.getProducer(), end.getConsumer(), end.getSession(), end.getMessageMonitor(), end.getExceptionMonitor());
}
/**
@@ -77,6 +89,7 @@ public class PublisherImpl extends CircuitEndBase implements Publisher
if (!connectionExceptionMonitor.assertNoExceptions())
{
passed = false;
+
addError("Was expecting no exceptions.\n");
addError("Got the following exceptions on the connection, "
+ circuit.getConnectionExceptionMonitor());
@@ -85,6 +98,7 @@ public class PublisherImpl extends CircuitEndBase implements Publisher
if (!sessionExceptionMonitor.assertNoExceptions())
{
passed = false;
+
addError("Was expecting no exceptions.\n");
addError("Got the following exceptions on the producer, " + circuit.getExceptionMonitor());
}
@@ -110,6 +124,8 @@ public class PublisherImpl extends CircuitEndBase implements Publisher
if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoConsumersException.class))
{
+ passed = false;
+
addError("Was expecting linked exception type " + AMQNoConsumersException.class.getName()
+ " on the connection.\n");
addError((connectionExceptionMonitor.size() > 0)
@@ -138,6 +154,8 @@ public class PublisherImpl extends CircuitEndBase implements Publisher
if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoRouteException.class))
{
+ passed = false;
+
addError("Was expecting linked exception type " + AMQNoRouteException.class.getName()
+ " on the connection.\n");
addError((connectionExceptionMonitor.size() > 0)
@@ -155,7 +173,7 @@ public class PublisherImpl extends CircuitEndBase implements Publisher
*
* @param circuit The containing circuit.
*/
- public void setCircuit(CircuitImpl circuit)
+ public void setCircuit(LocalCircuitImpl circuit)
{
this.circuit = circuit;
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalReceiverImpl.java
index 6dd7056806..1b5acf92de 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/LocalReceiverImpl.java
@@ -20,18 +20,17 @@
*/
package org.apache.qpid.test.framework.localcircuit;
-import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
-import org.apache.qpid.test.framework.CircuitEndBase;
-import org.apache.qpid.test.framework.Receiver;
-import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.*;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
/**
- * Provides an implementation of the {@link org.apache.qpid.test.framework.Receiver} interface that wraps a single message producer and consumer on
- * a single session.
+ * Provides an implementation of the {@link Receiver} interface that wraps a single message producer and consumer on
+ * a single controlSession, as a {@link CircuitEnd}. A local receiver also acts as a circuit end, because for a locally
+ * located circuit the assertions may be applied directly, there does not need to be any inter process messaging
+ * between the publisher and its single circuit end, in order to ascertain its status.
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
@@ -41,21 +40,32 @@ import javax.jms.Session;
* <tr><td> Provide assertion that the receivers received all test messages sent to it.
* </table>
*/
-public class ReceiverImpl extends CircuitEndBase implements Receiver
+public class LocalReceiverImpl extends CircuitEndBase implements Receiver
{
/** Holds a reference to the containing circuit. */
- private CircuitImpl circuit;
+ private LocalCircuitImpl circuit;
/**
- * Creates a circuit end point on the specified producer, consumer and session.
+ * Creates a circuit end point on the specified producer, consumer and controlSession.
*
* @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.
+ * @param session The controlSession for the circuit end point.
*/
- public ReceiverImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ public LocalReceiverImpl(MessageProducer producer, MessageConsumer consumer, Session session,
+ MessageMonitor messageMonitor, ExceptionMonitor exceptionMonitor)
{
- super(producer, consumer, session);
+ super(producer, consumer, session, messageMonitor, exceptionMonitor);
+ }
+
+ /**
+ * Creates a circuit end point from the producer, consumer and controlSession in a circuit end base implementation.
+ *
+ * @param end The circuit end base implementation to take producers and consumers from.
+ */
+ public LocalReceiverImpl(CircuitEndBase end)
+ {
+ super(end.getProducer(), end.getConsumer(), end.getSession(), end.getMessageMonitor(), end.getExceptionMonitor());
}
/**
@@ -83,7 +93,7 @@ public class ReceiverImpl extends CircuitEndBase implements Receiver
*
* @param circuit The containing circuit.
*/
- public void setCircuit(CircuitImpl circuit)
+ public void setCircuit(LocalCircuitImpl circuit)
{
this.circuit = circuit;
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseCircuitFactory.java
index a0e3d3b4a6..555071760e 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseCircuitFactory.java
@@ -22,9 +22,8 @@ package org.apache.qpid.test.framework.sequencers;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
-import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.util.ConversationFactory;
import java.util.LinkedList;
@@ -37,10 +36,10 @@ import java.util.Properties;
* <tr><td>
* </table>
*/
-public abstract class BaseDistributedTestSequencer implements DistributedTestSequencer
+public abstract class BaseCircuitFactory implements CircuitFactory
{
/** Used for debugging. */
- private final Logger log = Logger.getLogger(DistributedTestCase.class);
+ private final Logger log = Logger.getLogger(BaseCircuitFactory.class);
/** Holds the contact details for the sending test client. */
protected TestClientDetails sender;
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/CircuitFactory.java
index 4f09642467..82caa20d79 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/CircuitFactory.java
@@ -22,6 +22,8 @@ package org.apache.qpid.test.framework.sequencers;
import org.apache.qpid.test.framework.Assertion;
import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
@@ -41,8 +43,14 @@ import java.util.Properties;
* <tr><td> Provide a standard test procedure over a test circuit.
* <tr><td> Construct test circuits appropriate to a tests context.
* </table>
+ *
+ * @todo The sequence test method is deprecated, in favour of using test circuits instead. This interface might be
+ * better renamed to somethign like CircuitFactory, also the split between this interface and
+ * DistributedTestSequencer could be removed and DistributedTestCase functionality merged into FrameworkBaseCase.
+ * This is so that any test case written on top of the framework base case can be distributed, without having
+ * to extend a different base test class.
*/
-public interface TestCaseSequencer
+public interface CircuitFactory
{
/**
* Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
@@ -52,6 +60,8 @@ public interface TestCaseSequencer
* @param testCircuit The test circuit.
* @param assertions The list of assertions to apply to the test circuit.
* @param testProperties The test case definition.
+ *
+ * @deprecated Use test circuits and Circuit.test instead.
*/
public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties);
@@ -63,4 +73,39 @@ public interface TestCaseSequencer
* @return A test circuit.
*/
public Circuit createCircuit(ParsedProperties testProperties);
+
+ /**
+ * Sets the sender test client to coordinate the test with.
+ *
+ * @param sender The contact details of the sending client in the test.
+ */
+ public void setSender(TestClientDetails sender);
+
+ /**
+ * Sets the receiving test client to coordinate the test with.
+ *
+ * @param receiver The contact details of the sending client in the test.
+ */
+ public void setReceiver(TestClientDetails receiver);
+
+ /**
+ * Supplies the sending test client.
+ *
+ * @return The sending test client.
+ */
+ public TestClientDetails getSender();
+
+ /**
+ * Supplies the receiving test client.
+ *
+ * @return The receiving test client.
+ */
+ public List<TestClientDetails> getReceivers();
+
+ /**
+ * Accepts the conversation factory over which to hold the test coordinating conversation.
+ *
+ * @param conversationFactory The conversation factory to coordinate the test over.
+ */
+ public void setConversationFactory(ConversationFactory conversationFactory);
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java
deleted file mode 100644
index 73e61ec921..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java
+++ /dev/null
@@ -1,75 +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.test.framework.sequencers;
-
-import org.apache.qpid.test.framework.TestClientDetails;
-import org.apache.qpid.util.ConversationFactory;
-
-import java.util.List;
-
-/**
- * A DistributedTestSequencer is a test sequencer that coordinates activity amongst many
- * {@link org.apache.qpid.test.framework.distributedtesting.TestClient}s.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Accept notification of test case participants.
- * <tr><td> Accept JMS Connection to carry out the coordination over.
- * <tr><td> Coordinate a test sequence amongst participants. <td> {@link ConversationFactory}
- * </table>
- */
-public interface DistributedTestSequencer extends TestCaseSequencer
-{
- /**
- * Sets the sender test client to coordinate the test with.
- *
- * @param sender The contact details of the sending client in the test.
- */
- public void setSender(TestClientDetails sender);
-
- /**
- * Sets the receiving test client to coordinate the test with.
- *
- * @param receiver The contact details of the sending client in the test.
- */
- public void setReceiver(TestClientDetails receiver);
-
- /**
- * Supplies the sending test client.
- *
- * @return The sending test client.
- */
- public TestClientDetails getSender();
-
- /**
- * Supplies the receiving test client.
- *
- * @return The receiving test client.
- */
- public List<TestClientDetails> getReceivers();
-
- /**
- * Accepts the conversation factory over which to hold the test coordinating conversation.
- *
- * @param conversationFactory The conversation factory to coordinate the test over.
- */
- public void setConversationFactory(ConversationFactory conversationFactory);
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutCircuitFactory.java
index a116b23065..673b47df03 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutCircuitFactory.java
@@ -22,10 +22,11 @@ package org.apache.qpid.test.framework.sequencers;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.Assertion;
import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.distributedcircuit.DistributedCircuitImpl;
import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
@@ -35,19 +36,55 @@ import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
+import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
/**
+ * FanOutCircuitFactory is a circuit factory that creates distributed test circuits. Given a set of participating
+ * test client nodes, it assigns one node to the SENDER role and the remainder to the RECEIVER role.
+ *
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* <tr><td>
* </table>
+ *
+ * @todo Adapt this to be an n*m topology circuit factory. Need to add circuit topology definitions to the test
+ * parameters. Place n senders onto the available test clients, and m receivers. Where n or m is larger than
+ * the available nodes, start stacking multiple test clients on each node. There will also be an option that
+ * indicates whether nodes can play both roles, and how many nodes out of all available may be assigned to
+ * each role.
+ *
+ * @todo The createCircuit methods on this and InteropCircuitFactory are going to be identical. This is because the
+ * partitioning into senders and receivers is already done by the test decorators. Either eliminate these factories
+ * as unnesesary, or move the partitioning functionaility into the factories, in which case the test decorators
+ * can probably be merged or eliminated. There is confusion over the placement of responsibilities between the
+ * factories and the test decorators... although the test decorators may well do more than just circuit creation
+ * in the future. For example, there may have to be a special decorator for test repetition that does one circuit
+ * creation, but the runs many tests over it, in which case the handling of responsibilities becomes clearer.
*/
-public class FanOutTestSequencer extends BaseDistributedTestSequencer
+public class FanOutCircuitFactory extends BaseCircuitFactory
{
/** Used for debugging. */
- Logger log = Logger.getLogger(FanOutTestSequencer.class);
+ Logger log = Logger.getLogger(FanOutCircuitFactory.class);
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties)
+ {
+ log.debug("public Circuit createCircuit(ParsedProperties testProperties): called");
+
+ List<TestClientDetails> senders = new LinkedList<TestClientDetails>();
+ senders.add(getSender());
+ List<TestClientDetails> receivers = getReceivers();
+ ConversationFactory conversationFactory = getConversationFactory();
+
+ return DistributedCircuitImpl.createCircuit(testProperties, senders, receivers, conversationFactory);
+ }
/**
* Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
@@ -57,6 +94,8 @@ public class FanOutTestSequencer extends BaseDistributedTestSequencer
* @param testCircuit The test circuit.
* @param assertions The list of assertions to apply to the test circuit.
* @param testProperties The test case definition.
+ *
+ * @deprecated Scheduled for removal once existing tests converted over to use test circuits.
*/
public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties)
{
@@ -68,7 +107,7 @@ public class FanOutTestSequencer extends BaseDistributedTestSequencer
try
{
- // Create a conversation on the sender clients private control rouete.
+ // Create a conversation on the sender clients private control route.
Session session = conversationFactory.getSession();
Destination senderControlTopic = session.createTopic(sender.privateControlKey);
ConversationFactory.Conversation senderConversation = conversationFactory.startConversation();
@@ -117,17 +156,6 @@ public class FanOutTestSequencer extends BaseDistributedTestSequencer
}
/**
- * Creates a test circuit for the test, configered by the test parameters specified.
- *
- * @param testProperties The test parameters.
- * @return A test circuit.
- */
- public Circuit createCircuit(ParsedProperties testProperties)
- {
- throw new RuntimeException("Not implemented.");
- }
-
- /**
* Assigns the receivers role to the specified test client that is to act as a receivers during the test. This method
* does not always wait for the receiving clients to confirm their role assignments. This is because this method
* may be called from an 'onMessage' method, when a client is joining the test at a later point in time, and it
@@ -139,6 +167,8 @@ public class FanOutTestSequencer extends BaseDistributedTestSequencer
* @param confirm Indicates whether role confirmation should be waited for.
*
* @throws JMSException Any JMSExceptions occurring during the conversation are allowed to fall through.
+ *
+ * @deprecated Scheduled for removal once existing tests converted over to use test circuits.
*/
protected void assignReceiverRole(TestClientDetails receiver, Properties testProperties, boolean confirm)
throws JMSException
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropCircuitFactory.java
index f2253d416b..fa4e43e6d6 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropCircuitFactory.java
@@ -22,10 +22,11 @@ package org.apache.qpid.test.framework.sequencers;
import org.apache.log4j.Logger;
-import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.Assertion;
import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.distributedcircuit.DistributedCircuitImpl;
import org.apache.qpid.util.ConversationFactory;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
@@ -35,6 +36,7 @@ import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
+import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
@@ -44,10 +46,28 @@ import java.util.Properties;
* <tr><td>
* </table>
*/
-public class InteropTestSequencer extends BaseDistributedTestSequencer
+public class InteropCircuitFactory extends BaseCircuitFactory
{
/** Used for debugging. */
- Logger log = Logger.getLogger(InteropTestSequencer.class);
+ Logger log = Logger.getLogger(InteropCircuitFactory.class);
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties)
+ {
+ log.debug("public Circuit createCircuit(ParsedProperties testProperties): called");
+
+ List<TestClientDetails> senders = new LinkedList<TestClientDetails>();
+ senders.add(getSender());
+ List<TestClientDetails> receivers = getReceivers();
+ ConversationFactory conversationFactory = getConversationFactory();
+
+ return DistributedCircuitImpl.createCircuit(testProperties, senders, receivers, conversationFactory);
+ }
/**
* Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
@@ -123,15 +143,4 @@ public class InteropTestSequencer extends BaseDistributedTestSequencer
throw new RuntimeException("JMSException not handled.");
}
}
-
- /**
- * Creates a test circuit for the test, configered by the test parameters specified.
- *
- * @param testProperties The test parameters.
- * @return A test circuit.
- */
- public Circuit createCircuit(ParsedProperties testProperties)
- {
- throw new RuntimeException("Not implemented.");
- }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java b/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java
index 0090bec3d0..a325e7025e 100644
--- a/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java
+++ b/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java
@@ -87,7 +87,7 @@ import java.util.concurrent.atomic.AtomicLong;
*
* <p/>Conversation correlation id's are generated on a per thread basis.
*
- * <p/>The same session is shared amongst all conversations. Calls to send are therefore synchronized because JMS
+ * <p/>The same controlSession is shared amongst all conversations. Calls to send are therefore synchronized because JMS
* sessions are not multi-threaded.
*
* <p/><table id="crc"><caption>CRC Card</caption>
@@ -108,7 +108,7 @@ public class ConversationFactory
/** Holds the connection over which the conversation is conducted. */
private Connection connection;
- /** Holds the session over which the conversation is conduxted. */
+ /** Holds the controlSession over which the conversation is conduxted. */
private Session session;
/** The message consumer for incoming messages. */
@@ -219,9 +219,9 @@ public class ConversationFactory
}
/**
- * Gets the session over which the conversation is conducted.
+ * Gets the controlSession over which the conversation is conducted.
*
- * @return The session over which the conversation is conducted.
+ * @return The controlSession over which the conversation is conducted.
*/
public Session getSession()
{