From c024ccbbf310a6d964bc1dd6a65aff07a107f655 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 20 Mar 2007 17:23:47 +0000 Subject: Merged revisions 520415 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r520415 | rgreig | 2007-03-20 14:59:07 +0000 (Tue, 20 Mar 2007) | 1 line Improvements made to interop tests. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@520487 13f79535-47bb-0310-9956-ffa450edef68 --- java/integrationtests/pom.xml | 9 + .../interop/coordinator/CoordinatingTestCase.java | 112 +++++++++--- .../qpid/interop/coordinator/Coordinator.java | 197 ++++++++++++++++---- .../interop/coordinator/InvitingTestDecorator.java | 199 +++++++++++++++++++++ .../qpid/interop/coordinator/OptOutTestCase.java | 52 ++++++ .../interop/coordinator/TestClientDetails.java | 52 +++++- .../apache/qpid/interop/testclient/TestClient.java | 25 ++- .../testclient/testcases/TestCase1DummyRun.java | 14 ++ .../org/apache/qpid/util/ClasspathScanner.java | 15 +- .../org/apache/qpid/util/ConversationHelper.java | 36 +++- .../org/apache/qpid/interop/connection.properties | 2 + 11 files changed, 636 insertions(+), 77 deletions(-) create mode 100644 java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/InvitingTestDecorator.java create mode 100644 java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/OptOutTestCase.java create mode 100644 java/integrationtests/src/resources/org/apache/qpid/interop/connection.properties (limited to 'java/integrationtests') diff --git a/java/integrationtests/pom.xml b/java/integrationtests/pom.xml index 5e22cc7990..fd7ac8b039 100644 --- a/java/integrationtests/pom.xml +++ b/java/integrationtests/pom.xml @@ -107,6 +107,15 @@ + + + + false + src/resources + + **/* + + diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java index efeda78abf..f2c0acbc16 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/CoordinatingTestCase.java @@ -23,6 +23,9 @@ package org.apache.qpid.interop.coordinator; import java.util.Collection; import java.util.Properties; +import javax.jms.JMSException; +import javax.jms.Message; + import junit.framework.TestCase; import org.apache.qpid.util.ConversationHelper; @@ -55,61 +58,120 @@ import org.apache.qpid.util.ConversationHelper; * *

*
CRC Card
Responsibilities Collaborations + *
Accept notification of test case participants. {@link InvitingTestDecorator} *
Coordinate the test sequence amongst participants. {@link ConversationHelper} + *
Supply test properties *
*/ public abstract class CoordinatingTestCase extends TestCase { + /** Holds the contact details for the sending test client. */ + TestClientDetails sender; + + /** Holds the contact details for the receving test client. */ + TestClientDetails receiver; + + ConversationHelper conversation; + /** + * Creates a new coordinating test case with the specified name. * - * @param sender The contact details of the sending client in the test. - * @param receiver The contact details of the sending client in the test. - * @param allClients The list of all possible test clients that may accept the invitation. - * @param testProperties The test case definition. + * @param name The test case name. + */ + public CoordinatingTestCase(String name) + { + super(name); + } + + /** + * 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) + { + this.sender = 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) + { + this.receiver = receiver; + } + + /** + * Supplies the sending test client. + * + * @return The sending test client. + */ + public TestClientDetails getSender() + { + return sender; + } + + /** + * Supplies the receiving test client. + * + * @return The receiving test client. */ - public void TestCase(TestClientDetails sender, TestClientDetails receiver, Collection allClients, - Properties testProperties) - { } + public TestClientDetails getReceiver() + { + return receiver; + } /** * Holds a test coordinating conversation with the test clients. This is the basic implementation of the inner * loop of Use Case 5. It consists of assign the test roles, begining the test and gathering the test reports * from the participants. * - * @param sender The contact details of the sending client in the test. - * @param receiver The contact details of the receiving client in the test. - * @param allParticipatingClients The list of all clients accepted the invitation. - * @param testProperties The test case definition. + * @param testProperties The test case definition. * * @return The test results from the senders and receivers. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - protected Object[] sequenceTest(TestClientDetails sender, TestClientDetails receiver, Properties testProperties) + protected Object[] sequenceTest(Properties testProperties) throws JMSException { - // Check if the sender and recevier did not accept the invite to this test. - { - // Automatically fail this combination of sender and receiver. - } - // Assign the sender role to the sending test client. + Message assignSender = conversation.getSession().createMessage(); + assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE"); + assignSender.setStringProperty("ROLE", "SENDER"); + + conversation.send(assignSender); // Assign the receiver role the receiving client. + Message assignReceiver = conversation.getSession().createMessage(); + assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE"); + assignReceiver.setStringProperty("ROLE", "RECEIVER"); + + conversation.send(assignReceiver); // Wait for the senders and receivers to confirm their roles. + conversation.receive(); + conversation.receive(); // Start the test. + Message start = conversation.getSession().createMessage(); + start.setStringProperty("CONTROL_TYPE", "START"); + + conversation.send(start); // Wait for the test sender to return its report. + Message senderReport = conversation.receive(); + + // Ask the receiver for its report. + Message statusRequest = conversation.getSession().createMessage(); + statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST"); - // As the receiver for its report. + conversation.send(statusRequest); // Wait for the receiver to send its report. + Message receiverReport = conversation.receive(); - return null; + return new Message[] { senderReport, receiverReport }; } - - /*protected void setUp() - { }*/ - - /*protected void tearDown() - { }*/ } diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java index 535b4ae014..3f87becc3d 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/Coordinator.java @@ -20,14 +20,26 @@ */ package org.apache.qpid.interop.coordinator; -import java.util.Properties; +import java.util.*; +import java.util.concurrent.LinkedBlockingQueue; + +import javax.jms.*; import junit.framework.Test; import junit.framework.TestResult; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; +import org.apache.qpid.interop.testclient.InteropClientTestCase; +import org.apache.qpid.interop.testclient.TestClient; +import org.apache.qpid.util.ClasspathScanner; import org.apache.qpid.util.CommandLineParser; +import org.apache.qpid.util.ConversationHelper; +import org.apache.qpid.util.PrettyPrintingUtils; import uk.co.thebadgerset.junit.extensions.TestRunnerImprovedErrorHandling; +import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator; /** *

Implements the coordinator client described in the interop testing specification @@ -36,20 +48,27 @@ import uk.co.thebadgerset.junit.extensions.TestRunnerImprovedErrorHandling; * *

*
CRC Card
Responsibilities Collaborations - *
Find out what test clients are available. - *
Decorate available tests to run all available clients. + *
Find out what test clients are available. {@link ConversationHelper} + *
Decorate available tests to run all available clients. {@link InvitingTestDecorator} *
Attach XML test result logger. *
Terminate the interop testing framework. *
*/ public class Coordinator extends TestRunnerImprovedErrorHandling { + private static final Logger log = Logger.getLogger(Coordinator.class); + + public static final String DEFAULT_CONNECTION_PROPS_RESOURCE = "org/apache/qpid/interop/connection.properties"; + /** Holds the URL of the broker to coordinate the tests on. */ String brokerUrl; /** Holds the virtual host to coordinate the tests on. If null, then the default virtual host is used. */ String virtualHost; + /** Holds the list of all clients that enlisted, when the compulsory invite was issued. */ + Set enlistedClients = new HashSet(); + /** * Creates an interop test coordinator on the specified broker and virtual host. * @@ -58,6 +77,8 @@ public class Coordinator extends TestRunnerImprovedErrorHandling */ Coordinator(String brokerUrl, String virtualHost) { + log.debug("Coordinator(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost + "): called"); + // Retain the connection parameters. this.brokerUrl = brokerUrl; this.virtualHost = virtualHost; @@ -76,42 +97,51 @@ public class Coordinator extends TestRunnerImprovedErrorHandling */ public static void main(String[] args) { - // Use the command line parser to evaluate the command line. - CommandLineParser commandLine = - new CommandLineParser(new String[][] - { - { "b", "The broker URL.", "broker", "true" }, - { "h", "The virtual host to use.", "virtual host", "false" } - }); - - // Capture the command line arguments or display errors and correct usage and then exit. - Properties options = null; - try { - options = commandLine.parseCommandLine(args); - } - catch (IllegalArgumentException e) - { - System.out.println(commandLine.getErrors()); - System.out.println(commandLine.getUsage()); - System.exit(1); - } + // Use the command line parser to evaluate the command line. + CommandLineParser commandLine = + new CommandLineParser(new String[][] + { + { "b", "The broker URL.", "broker", "false" }, + { "h", "The virtual host to use.", "virtual host", "false" } + }); - // Extract the command line options. - String brokerUrl = options.getProperty("b"); - String virtualHost = options.getProperty("h"); + // Capture the command line arguments or display errors and correct usage and then exit. + Properties options = null; - // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up - // overridden values from there. - commandLine.addCommandLineToSysProperties(); + try + { + options = commandLine.parseCommandLine(args); + } + catch (IllegalArgumentException e) + { + System.out.println(commandLine.getErrors()); + System.out.println(commandLine.getUsage()); + System.exit(1); + } - // Scan for available test cases using a classpath scanner. - String[] testClassNames = null; + // Extract the command line options. + String brokerUrl = options.getProperty("b"); + String virtualHost = options.getProperty("h"); - // Create a coordinator and begin its test procedure. - try - { + // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up + // overridden values from there. + commandLine.addCommandLineToSysProperties(); + + // Scan for available test cases using a classpath scanner. + Collection> testCaseClasses = + ClasspathScanner.getMatches(CoordinatingTestCase.class, "^Test.*", true); + + int i = 0; + String[] testClassNames = new String[testCaseClasses.size()]; + + for (Class testClass : testCaseClasses) + { + testClassNames[i++] = testClass.getName(); + } + + // Create a coordinator and begin its test procedure. Coordinator coordinator = new Coordinator(brokerUrl, virtualHost); TestResult testResult = coordinator.start(testClassNames); @@ -127,31 +157,92 @@ public class Coordinator extends TestRunnerImprovedErrorHandling catch (Exception e) { System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); System.exit(EXCEPTION_EXIT); } } + /** + * Starts all of the test classes to be run by this coordinator running. + * + * @param testClassNames An array of all the coordinating test case implementations. + * + * @return A JUnit TestResult to run the tests with. + * + * @throws Exception Any underlying exceptions are allowed to fall through, and fail the test process. + */ public TestResult start(String[] testClassNames) throws Exception { + log.debug("public TestResult start(String[] testClassNames = " + PrettyPrintingUtils.printArray(testClassNames) + + "): called"); + // Connect to the broker. + Connection connection = TestClient.createConnection(DEFAULT_CONNECTION_PROPS_RESOURCE, brokerUrl, virtualHost); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination controlTopic = session.createTopic("iop.control"); + Destination responseQueue = session.createQueue("coordinator"); + + ConversationHelper conversation = + new ConversationHelper(connection, controlTopic, responseQueue, LinkedBlockingQueue.class); // Broadcast the compulsory invitation to find out what clients are available to test. + Message invite = session.createMessage(); + invite.setStringProperty("CONTROL_TYPE", "INVITE"); + invite.setJMSReplyTo(responseQueue); + + conversation.send(invite); // Wait for a short time, to give test clients an opportunity to reply to the invitation. + Collection enlists = conversation.receiveAll(0, 10000); - // Retain the list of all available clients. + enlistedClients = extractEnlists(enlists); // Run all of the tests in the suite using JUnit. TestResult result = super.start(testClassNames); // At this point in time, all tests have completed. Broadcast the shutdown message. + Message terminate = session.createMessage(); + terminate.setStringProperty("CONTROL_TYPE", "TERMINATE"); + + conversation.send(terminate); return result; } + /** + * For a collection of enlist messages, this method pulls out of the client details for the enlisting clients. + * + * @param enlists The enlist messages. + * + * @return A set of enlisting clients, extracted from the enlist messages. + * + * @throws JMSException Any underlying JMSException is allowed to fall through. + */ + public static Set extractEnlists(Collection enlists) throws JMSException + { + log.debug("public static Set extractEnlists(Collection enlists = " + enlists + + "): called"); + + Set enlistedClients = new HashSet(); + + // Retain the list of all available clients. + for (Message enlist : enlists) + { + TestClientDetails clientDetails = new TestClientDetails(); + clientDetails.clientName = enlist.getStringProperty("CLIENT_NAME"); + clientDetails.privateControlKey = enlist.getStringProperty("CLIENT_PRIVATE_CONTROL_KEY"); + + enlistedClients.add(clientDetails); + } + + return enlistedClients; + } + /** * Runs a test or suite of tests, using the super class implemenation. This method wraps the test to be run - * in any test decorators needed to add in the configured toolkits enhanced junit functionality. + * in any test decorators needed to add in the coordinators ability to invite test clients to participate in + * tests. * * @param test The test to run. * @param wait Undocumented. Nothing in the JUnit javadocs to say what this is for. @@ -160,9 +251,39 @@ public class Coordinator extends TestRunnerImprovedErrorHandling */ public TestResult doRun(Test test, boolean wait) { - // Combine together the available test cases and test clients to produce a complete list of test case instances - // to run as a JUnit test suite. + log.debug("public TestResult doRun(Test \"" + test + "\", boolean " + wait + "): called"); + + // Wrap all tests in the test suite with WrappedSuiteTestDecorators. This is quite ugly and a bit baffling, + // but the reason it is done is because the JUnit implementation of TestDecorator has some bugs in it. + WrappedSuiteTestDecorator targetTest = null; + + if (test instanceof TestSuite) + { + log.debug("targetTest is a TestSuite"); + + TestSuite suite = (TestSuite) test; + + int numTests = suite.countTestCases(); + log.debug("There are " + numTests + " in the suite."); + + for (int i = 0; i < numTests; i++) + { + Test nextTest = suite.testAt(i); + log.debug("suite.testAt(" + i + ") = " + nextTest); + + if (nextTest instanceof CoordinatingTestCase) + { + log.debug("nextTest is a CoordinatingTestCase"); + } + } + + targetTest = new WrappedSuiteTestDecorator(suite); + log.debug("Wrapped with a WrappedSuiteTestDecorator."); + } + + // Wrap the tests in an inviting test decorator, to perform the invite/test cycle. + targetTest = new InvitingTestDecorator(targetTest, enlistedClients); - return null; + return super.doRun(targetTest, wait); } } diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/InvitingTestDecorator.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/InvitingTestDecorator.java new file mode 100644 index 0000000000..64770be654 --- /dev/null +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/InvitingTestDecorator.java @@ -0,0 +1,199 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.interop.coordinator; + +import java.util.*; + +import javax.jms.JMSException; +import javax.jms.Message; + +import junit.framework.Test; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.util.ConversationHelper; + +import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator; + +/** + *

+ *
CRC Card
Responsibilities Collaborations + *
Broadcast test invitations and collect enlists. {@link ConversationHelper}. + *
Output test failures for clients unwilling to run the test case. {@link Coordinator} + *
Execute coordinated test cases. {@link CoordinatingTestCase} + *
+ */ +public class InvitingTestDecorator extends WrappedSuiteTestDecorator +{ + private static final Logger log = Logger.getLogger(InvitingTestDecorator.class); + + Set allClients; + ConversationHelper conversation; + + WrappedSuiteTestDecorator testSuite; + + /** + * Creates a wrappred suite test decorator from a test suite. + * + * @param suite The test suite. + * @param allClients The list of all clients that responded to the compulsory invite. + */ + /*public InvitingTestDecorator(TestSuite suite, Collection allClients, ConversationHelper conversation) + { + super(suite); + }*/ + + /** + * Creates a wrapped suite test decorator from another one. + * + * @param suite The test suite. + * @param allClients The list of all clients that responded to the compulsory invite. + */ + public InvitingTestDecorator(WrappedSuiteTestDecorator suite, Set allClients) + { + super(suite); + + log.debug("public InvitingTestDecorator(WrappedSuiteTestDecorator suite, Set allClients = " + + allClients + "): called"); + } + + /** + * 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 CoordinatingTestCase}. + * + *

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. + * + * @todo Better error recovery for failure of the invite/enlist conversation could be added. + * + * @param testResult The the results object to monitor the test results with. + */ + public void run(TestResult testResult) + { + log.debug("public void run(TestResult testResult): called"); + + Collection tests = testSuite.getAllUnderlyingTests(); + + for (Test test : tests) + { + CoordinatingTestCase coordTest = (CoordinatingTestCase) test; + + // Broadcast the invitation to find out what clients are available to test. + Set enlists = null; + try + { + Message invite = conversation.getSession().createMessage(); + invite.setStringProperty("CONTROL_TYPE", "INVITE"); + invite.setStringProperty("TEST_NAME", coordTest.getName()); + + conversation.send(invite); + + // Wait for a short time, to give test clients an opportunity to reply to the invitation. + Collection replies = conversation.receiveAll(allClients.size(), 10000); + enlists = Coordinator.extractEnlists(replies); + } + catch (JMSException e) + { + throw new RuntimeException("There was a JMSException during the invite/enlist conversation.", e); + } + + // Compare the list of willing clients to the list of all available. + Set optOuts = new HashSet(allClients); + optOuts.removeAll(enlists); + + // Output test failures for clients that will not particpate in the test. + Set> failPairs = allPairs(optOuts, allClients); + + for (List failPair : failPairs) + { + CoordinatingTestCase failTest = new OptOutTestCase(""); + failTest.setSender(failPair.get(0)); + failTest.setReceiver(failPair.get(1)); + + failTest.run(testResult); + } + + // Loop over all combinations of clients, willing to run the test. + Set> enlistedPairs = allPairs(enlists, enlists); + + for (List enlistedPair : enlistedPairs) + { + // Set the sending and receiving client details on the test case. + coordTest.setSender(enlistedPair.get(0)); + coordTest.setReceiver(enlistedPair.get(1)); + + // Execute the test case. + coordTest.run(testResult); + } + } + } + + /** + * Produces all pairs of combinations of elements from two sets. The ordering of the elements in the pair is + * important, that is the pair is distinct from ; both pairs are generated. For any element, i, in + * both the left and right sets, the reflexive pair is not generated. + * + * @param left The left set. + * @param right The right set. + * + * @return All pairs formed from the permutations of all elements of the left and right sets. + */ + private Set> allPairs(Set left, Set right) + { + log.debug("private Set> allPairs(Set left = " + left + ", Set right = " + right + "): called"); + + Set> results = new HashSet>(); + + // Form all pairs from left to right. + // Form all pairs from right to left. + for (E le : left) + { + for (E re : right) + { + if (!le.equals(re)) + { + results.add(new Pair(le, re)); + results.add(new Pair(re, le)); + } + } + } + + log.debug("results = " + results); + + return results; + } + + /** + * A simple implementation of a pair, using a list. + */ + private class Pair extends ArrayList + { + public Pair(T first, T second) + { + super(); + super.add(first); + super.add(second); + } + } +} diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/OptOutTestCase.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/OptOutTestCase.java new file mode 100644 index 0000000000..27e2c42a9a --- /dev/null +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/OptOutTestCase.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.interop.coordinator; + +import junit.framework.Assert; + +/** + * An OptOutTestCase is a test case that automatically fails. It is used when a list of test clients has been generated + * from a compulsory invite, but only some of those clients have responded to a specific test case invite. The clients + * that did not respond, are automatically given a fail for the test. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Fail the test with a suitable reason. + *
+ */ +public class OptOutTestCase extends CoordinatingTestCase +{ + /** + * Creates a new coordinating test case with the specified name. + * + * @param name The test case name. + */ + public OptOutTestCase(String name) + { + super(name); + } + + /** Generates an appropriate test failure assertion. */ + public void testOptOut() + { + Assert.fail("One of " + getSender() + " and " + getReceiver() + " opted out of the test."); + } +} diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java index fcfb5a08fd..80abd4d4c9 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/coordinator/TestClientDetails.java @@ -30,8 +30,58 @@ public class TestClientDetails /** The test clients name. */ public String clientName; - /* The test clients unqiue sequence number. Not currently used. */ + /* The test clients unique sequence number. Not currently used. */ /** The routing key of the test clients control topic. */ public String privateControlKey; + + /** + * Two TestClientDetails are considered to be equal, iff they have the same client name. + * + * @param o The object to compare to. + * + * @return If the object to compare to is a TestClientDetails equal to this one, false otherwise. + */ + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + + if (!(o instanceof TestClientDetails)) + { + return false; + } + + final TestClientDetails testClientDetails = (TestClientDetails) o; + + if ((clientName != null) ? (!clientName.equals(testClientDetails.clientName)) + : (testClientDetails.clientName != null)) + { + return false; + } + + return true; + } + + /** + * Computes a hash code compatible with the equals method; based on the client name alone. + * + * @return A hash code for this. + */ + public int hashCode() + { + return ((clientName != null) ? clientName.hashCode() : 0); + } + + /** + * Outputs the client name and address details. Mostly used for debugging purposes. + * + * @return The client name and address. + */ + public String toString() + { + return "clientName = " + clientName + ", privateControlKey = " + privateControlKey; + } } diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java index a623687a0f..6d7ab9c978 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/TestClient.java @@ -75,13 +75,16 @@ public class TestClient implements MessageListener public static final String CONNECTION_PROPERTY = "connectionfactory.broker"; public static final String CONNECTION_NAME = "broker"; public static final String CLIENT_NAME = "java"; - public static final String DEFAULT_CONNECTION_PROPS_RESOURCE = "org/apache/qpid/interop/client/connection.properties"; + public static final String DEFAULT_CONNECTION_PROPS_RESOURCE = "org/apache/qpid/interop/connection.properties"; private MessageProducer producer; private Session session; public TestClient(String brokerUrl, String virtualHost) { + log.debug("public TestClient(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost + + "): called"); + // Retain the connection parameters. this.brokerUrl = brokerUrl; this.virtualHost = virtualHost; @@ -104,7 +107,7 @@ public class TestClient implements MessageListener CommandLineParser commandLine = new CommandLineParser(new String[][] { - { "b", "The broker URL.", "broker", "true" }, + { "b", "The broker URL.", "broker", "false" }, { "h", "The virtual host to use.", "virtual host", "false" } }); @@ -146,6 +149,8 @@ public class TestClient implements MessageListener private void start() throws JMSException { + log.debug("private void start(): called"); + // Use a class path scanner to find all the interop test case implementations. Collection> testCaseClasses = ClasspathScanner.getMatches(InteropClientTestCase.class, "^TestCase.*", true); @@ -201,17 +206,23 @@ public class TestClient implements MessageListener * * @return A JMS conneciton. */ - private static Connection createConnection(String connectionPropsResource, String brokerUrl, String virtualHost) + public static Connection createConnection(String connectionPropsResource, String brokerUrl, String virtualHost) { + log.debug("public static Connection createConnection(String connectionPropsResource = " + connectionPropsResource + + ", String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost + "): called"); + try { Properties connectionProps = PropertiesUtils.getProperties(TestClient.class.getClassLoader().getResourceAsStream( connectionPropsResource)); - String connectionString = - "amqp://guest:guest/" + ((virtualHost != null) ? virtualHost : "") + "?brokerlist='" + brokerUrl + "'"; - connectionProps.setProperty(CONNECTION_PROPERTY, connectionString); + if (brokerUrl != null) + { + String connectionString = + "amqp://guest:guest/" + ((virtualHost != null) ? virtualHost : "") + "?brokerlist='" + brokerUrl + "'"; + connectionProps.setProperty(CONNECTION_PROPERTY, connectionString); + } Context ctx = new InitialContext(connectionProps); @@ -241,6 +252,8 @@ public class TestClient implements MessageListener */ public void onMessage(Message message) { + log.debug("public void onMessage(Message message = " + message + "): called"); + try { String controlType = message.getStringProperty("CONTROL_TYPE"); diff --git a/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java b/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java index 570e4ff25c..aa31a59b06 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/interop/testclient/testcases/TestCase1DummyRun.java @@ -24,6 +24,8 @@ import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Session; +import org.apache.log4j.Logger; + import org.apache.qpid.interop.testclient.InteropClientTestCase; /** @@ -41,29 +43,41 @@ import org.apache.qpid.interop.testclient.InteropClientTestCase; */ public class TestCase1DummyRun implements InteropClientTestCase { + private static final Logger log = Logger.getLogger(TestCase1DummyRun.class); + public String getName() { + log.debug("public String getName(): called"); + return "TC1_DummyRun"; } public boolean acceptInvite(Message inviteMessage) throws JMSException { + log.debug("public boolean acceptInvite(Message inviteMessage): called"); + // Test parameters don't matter, accept all invites. return true; } public void assignRole(Roles role, Message assignRoleMessage) throws JMSException { + log.debug("public void assignRole(Roles role, Message assignRoleMessage): called"); + // Do nothing, both roles are the same. } public void start() { + log.debug("public void start(): called"); + // Do nothing. } public Message getReport(Session session) throws JMSException { + log.debug("public Message getReport(Session session): 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/util/ClasspathScanner.java b/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java index 35946e6c4e..cd8e0a80a1 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/util/ClasspathScanner.java @@ -63,12 +63,17 @@ public class ClasspathScanner public static Collection> getMatches(Class matchingClass, String matchingRegexp, boolean beanOnly) { + log.debug("public static Collection> getMatches(Class matchingClass = " + matchingClass + + ", String matchingRegexp = " + matchingRegexp + ", boolean beanOnly = " + beanOnly + "): called"); + // Build a compiled regular expression from the pattern to match. Pattern matchPattern = Pattern.compile(matchingRegexp); String classPath = System.getProperty("java.class.path"); Map> result = new HashMap>(); + log.debug("classPath = " + classPath); + // Find matching classes starting from all roots in the classpath. for (String path : splitClassPath(classPath)) { @@ -92,15 +97,19 @@ public class ClasspathScanner private static void gatherFiles(File classRoot, String classFileName, Map> result, Pattern matchPattern, Class matchClass) { + log.debug("private static void gatherFiles(File classRoot = " + classRoot + ", String classFileName = " + + classFileName + ", Map> result, Pattern matchPattern = " + matchPattern + + ", Class matchClass = " + matchClass + "): called"); + File thisRoot = new File(classRoot, classFileName); // If the current location is a file, check if it is a matching class. if (thisRoot.isFile()) { // Check that the file has a matching name. - if (matchesName(classFileName, matchPattern)) + if (matchesName(thisRoot.getName(), matchPattern)) { - String className = classNameFromFile(classFileName); + String className = classNameFromFile(thisRoot.getName()); // Check that the class has matching type. try @@ -206,6 +215,8 @@ public class ClasspathScanner */ private static String classNameFromFile(String classFileName) { + log.debug("private static String classNameFromFile(String classFileName = " + classFileName + "): called"); + // Remove the .class ending. String s = classFileName.substring(0, classFileName.length() - ".class".length()); diff --git a/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java b/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java index 631cab9f35..9b0bc07ba9 100644 --- a/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java +++ b/java/integrationtests/src/main/java/org/apache/qpid/util/ConversationHelper.java @@ -21,7 +21,6 @@ package org.apache.qpid.util; import java.util.*; -import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicLong; @@ -109,7 +108,7 @@ public class ConversationHelper private MessageProducer producer; private MessageConsumer consumer; - Class> queueClass; + Class queueClass; BlockingQueue deadLetterBox = new LinkedBlockingQueue(); @@ -140,7 +139,7 @@ public class ConversationHelper * @throws JMSException All undelying JMSExceptions are allowed to fall through. */ public ConversationHelper(Connection connection, Destination sendDestination, Destination receiveDestination, - Class> queueClass) throws JMSException + Class queueClass) throws JMSException { session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(sendDestination); @@ -180,7 +179,7 @@ public class ConversationHelper { if (!idsToQueues.containsKey(conversationId)) { - idsToQueues.put(conversationId, ReflectionUtils.>newInstance(queueClass)); + idsToQueues.put(conversationId, ReflectionUtils.newInstance(queueClass)); } } @@ -209,6 +208,28 @@ public class ConversationHelper } } + /** + * Gets many messages in an ongoing conversation. If a limit is specified, then once that many messages are + * received they will be returned. If a timeout is specified, then all messages up to the limit, received within + * that timespan will be returned. + * + * @param num The number of messages to receive, or all if this is less than 1. + * @param timeout The timeout in milliseconds to receive the messages in, or forever if this is less than 1. + * + * @return All messages received within the count limit and the timeout. + */ + public Collection receiveAll(int num, long timeout) + { + Collection result = new ArrayList(); + + for (int i = 0; i < num; i++) + { + result.add(receive()); + } + + return result; + } + /** * Completes the conversation. Any open transactions are committed. Any correlation id's pertaining to the * conversation are no longer valid, and any incoming messages using them will go to the dead letter box. @@ -234,7 +255,7 @@ public class ConversationHelper */ public Collection emptyDeadLetterBox() { - Collection result = new LinkedList(); + Collection result = new ArrayList(); deadLetterBox.drainTo(result); return result; @@ -280,4 +301,9 @@ public class ConversationHelper /** Holds the correlation id for the current threads conversation. */ long conversationId; } + + public Session getSession() + { + return session; + } } diff --git a/java/integrationtests/src/resources/org/apache/qpid/interop/connection.properties b/java/integrationtests/src/resources/org/apache/qpid/interop/connection.properties new file mode 100644 index 0000000000..357b33bb8a --- /dev/null +++ b/java/integrationtests/src/resources/org/apache/qpid/interop/connection.properties @@ -0,0 +1,2 @@ +java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory +connectionfactory.broker = amqp://guest:guest@clientid/?brokerlist='tcp://localhost:5672' -- cgit v1.2.1