summaryrefslogtreecommitdiff
path: root/qpid/java/perftests/src
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2012-04-05 16:04:10 +0000
committerRobert Gemmell <robbie@apache.org>2012-04-05 16:04:10 +0000
commiteb58a828676bf1fad33c317f86a909f18cadacbc (patch)
treeaef0634df4867e761ea65792d5e19eacbc029f49 /qpid/java/perftests/src
parent347ee6bc0e71ca79d729ccf53c134fbe01289621 (diff)
downloadqpid-python-eb58a828676bf1fad33c317f86a909f18cadacbc.tar.gz
QPID-3936: initial checkin of new testing framework, initially to be used for performance testing but later to be expanded for use with other testing scenarios.
Applied patch from Philip Harvey <phil@philharveyonline.com>, Oleksandr Rudyy <orudyy@gmail.com>, Andrew MacBean <andymacbean@gmail.com>, Keith Wall <kwall@apache.org>, and myself. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1309918 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/perftests/src')
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java74
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java44
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java94
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java179
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java33
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java66
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java76
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java204
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java98
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java25
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java235
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java212
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java31
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java132
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java45
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java94
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java158
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java68
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java27
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java122
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java179
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java27
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java46
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java47
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java129
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java79
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java52
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java46
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java31
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java227
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java94
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java49
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java70
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java307
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java31
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java113
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java81
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java52
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java91
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java65
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java86
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java60
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java64
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java90
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java69
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java114
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java117
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java102
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java575
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java210
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java124
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java110
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java31
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java43
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java147
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java56
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java39
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java118
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java58
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java108
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java54
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java96
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java106
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java28
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java62
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java30
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java35
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java67
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java89
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java231
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java100
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java43
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java80
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java29
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java28
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java29
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java97
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java49
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java36
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java124
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java98
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java89
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java55
-rw-r--r--qpid/java/perftests/src/main/resources/perftests.properties20
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java96
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java48
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java92
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java108
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java159
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java173
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java107
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java183
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java55
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java168
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java61
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java211
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java88
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java73
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java76
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java153
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java30
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java57
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java253
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java144
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java252
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java111
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java113
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java56
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java56
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java94
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java79
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java78
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java51
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java89
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java93
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java113
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java102
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json72
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java40
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java183
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java148
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java61
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java182
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java144
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java140
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java89
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv2
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java72
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java117
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java28
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java186
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java156
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java90
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java323
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java119
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java132
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java237
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json63
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json41
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json55
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json77
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json107
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java157
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json17
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java94
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json65
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties26
147 files changed, 14674 insertions, 0 deletions
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java
new file mode 100644
index 0000000000..9e865010f8
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * 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.disttest;
+
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+public class AbstractRunner
+{
+ public static final String JNDI_CONFIG_PROP = "jndi-config";
+ public static final String JNDI_CONFIG_DEFAULT = "perftests-jndi.properties";
+
+ private Map<String,String> _cliOptions = new HashMap<String, String>();
+ {
+ getCliOptions().put(JNDI_CONFIG_PROP, JNDI_CONFIG_DEFAULT);
+ }
+
+ protected Context getContext()
+ {
+ Context context = null;
+
+ try
+ {
+ final Properties properties = new Properties();
+ properties.load(new FileInputStream(getJndiConfig()));
+ context = new InitialContext(properties);
+ }
+ catch (Exception e)
+ {
+ throw new DistributedTestException("Exception while loading JNDI properties", e);
+ }
+
+ return context;
+ }
+
+ public void parseArgumentsIntoConfig(String[] args)
+ {
+ ArgumentParser argumentParser = new ArgumentParser();
+ argumentParser.parseArgumentsIntoConfig(getCliOptions(), args);
+ }
+
+ protected String getJndiConfig()
+ {
+ return getCliOptions().get(AbstractRunner.JNDI_CONFIG_PROP);
+ }
+
+ protected Map<String,String> getCliOptions()
+ {
+ return _cliOptions;
+ }
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java
new file mode 100644
index 0000000000..8c1f8675e3
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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.disttest;
+
+import java.util.Map;
+
+public class ArgumentParser
+{
+ public void parseArgumentsIntoConfig(Map<String, String> initialValues, String[] args)
+ {
+ for(String arg: args)
+ {
+ String[] splitArg = arg.split("=");
+ if(splitArg.length != 2)
+ {
+ throw new IllegalArgumentException("arguments must have format <name>=<value>: " + arg);
+ }
+
+ if(initialValues.put(splitArg[0], splitArg[1]) == null)
+ {
+ throw new IllegalArgumentException("not a valid configuration property: " + arg);
+ }
+ }
+
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java
new file mode 100644
index 0000000000..9c2f4a3d95
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java
@@ -0,0 +1,94 @@
+/*
+ * 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.disttest;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientRunner extends AbstractRunner
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ClientRunner.class);
+
+ public static final String NUM_OF_CLIENTS_PROP = "number-of-clients";
+
+ public static final String NUM_OF_CLIENTS_DEFAULT = "1";
+
+ public ClientRunner()
+ {
+ getCliOptions().put(NUM_OF_CLIENTS_PROP, NUM_OF_CLIENTS_DEFAULT);
+ }
+
+ public static void main(String[] args)
+ {
+ ClientRunner runner = new ClientRunner();
+ runner.parseArgumentsIntoConfig(args);
+ runner.runClients();
+ }
+
+ public void setJndiPropertiesFileLocation(String jndiConfigFileLocation)
+ {
+ getCliOptions().put(JNDI_CONFIG_PROP, jndiConfigFileLocation);
+ }
+
+ /**
+ * Run the clients in the background
+ */
+ public void runClients()
+ {
+ int numClients = Integer.parseInt(getCliOptions().get(NUM_OF_CLIENTS_PROP));
+
+ Context context = getContext();
+
+ for(int i = 1; i <= numClients; i++)
+ {
+ createBackgroundClient(context);
+ }
+ }
+
+ private void createBackgroundClient(Context context)
+ {
+ try
+ {
+ final Client client = new Client(new ClientJmsDelegate(context));
+
+ final Thread clientThread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ LOGGER.info("Starting client " + client.getClientName());
+ client.start();
+ client.waitUntilStopped();
+ LOGGER.info("Stopped client " + client.getClientName());
+ }
+ });
+ clientThread.start();
+ }
+ catch (NamingException e)
+ {
+ throw new DistributedTestException("Exception while creating client instance", e);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java
new file mode 100644
index 0000000000..07d78790f0
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java
@@ -0,0 +1,179 @@
+/*
+ * 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.disttest;
+
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.naming.Context;
+
+import org.apache.qpid.disttest.controller.Controller;
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.controller.config.ConfigReader;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.results.aggregation.Aggregator;
+import org.apache.qpid.disttest.results.formatting.CSVFormater;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ControllerRunner extends AbstractRunner
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ControllerRunner.class);
+
+ public static final String TEST_CONFIG_PROP = "test-config";
+ public static final String DISTRIBUTED_PROP = "distributed";
+ public static final String OUTPUT_FILE_PROP = "outputfile";
+
+ private static final String TEST_CONFIG_DEFAULT = "perftests-config.json";
+ private static final String DISTRIBUTED_DEFAULT = "false";
+ private static final String OUTPUT_FILE_DEFAULT = "output.csv";
+
+ private Controller _controller;
+
+ private final Aggregator _aggregator = new Aggregator();
+
+
+ public ControllerRunner()
+ {
+ getCliOptions().put(TEST_CONFIG_PROP, TEST_CONFIG_DEFAULT);
+ getCliOptions().put(DISTRIBUTED_PROP, DISTRIBUTED_DEFAULT);
+ getCliOptions().put(OUTPUT_FILE_PROP, OUTPUT_FILE_DEFAULT);
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ ControllerRunner runner = new ControllerRunner();
+ runner.parseArgumentsIntoConfig(args);
+ runner.runController();
+ }
+
+ public void runController() throws Exception
+ {
+ Context context = getContext();
+
+ ControllerJmsDelegate jmsDelegate = new ControllerJmsDelegate(context);
+
+ try
+ {
+ runTests(jmsDelegate);
+ }
+ finally
+ {
+ jmsDelegate.closeConnections();
+ }
+ }
+
+ private void runTests(ControllerJmsDelegate jmsDelegate)
+ {
+
+ _controller = new Controller(jmsDelegate,
+ DistributedTestConstants.REGISTRATION_TIMEOUT, DistributedTestConstants.COMMAND_RESPONSE_TIMEOUT);
+
+ Config testConfig = getTestConfig();
+ _controller.setConfig(testConfig);
+
+ if(!isDistributed())
+ {
+ //we must create the required test clients, running in single-jvm mode
+ int numClients = testConfig.getTotalNumberOfClients();
+ for (int i = 1; i <= numClients; i++)
+ {
+ ClientRunner clientRunner = new ClientRunner();
+ clientRunner.setJndiPropertiesFileLocation(getJndiConfig());
+ clientRunner.runClients();
+ }
+ }
+
+ ResultsForAllTests resultsForAllTests = null;
+ try
+ {
+ _controller.awaitClientRegistrations();
+
+ ResultsForAllTests rawResultsForAllTests = _controller.runAllTests();
+ resultsForAllTests = _aggregator.aggregateResults(rawResultsForAllTests);
+ }
+ finally
+ {
+ _controller.stopAllRegisteredClients();
+ }
+
+ final String outputFile = getOutputFile();
+ writeResultsToFile(resultsForAllTests, outputFile);
+ }
+
+ private void writeResultsToFile(ResultsForAllTests resultsForAllTests, String outputFile)
+ {
+ FileWriter writer = null;
+ try
+ {
+ final String outputCsv = new CSVFormater().format(resultsForAllTests);
+ writer = new FileWriter(outputFile);
+ writer.write(outputCsv);
+ LOGGER.info("Wrote " + resultsForAllTests.getTestResults().size() + " test result(s) to output file " + outputFile);
+ }
+ catch (IOException e)
+ {
+ throw new DistributedTestException("Unable to write output file " + outputFile, e);
+ }
+ finally
+ {
+ if (writer != null)
+ {
+ try
+ {
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ LOGGER.error("Failed to close stream for file " + outputFile, e);
+ }
+ }
+ }
+ }
+
+ private String getOutputFile()
+ {
+ return String.valueOf(getCliOptions().get(ControllerRunner.OUTPUT_FILE_PROP));
+ }
+
+ private Config getTestConfig()
+ {
+ ConfigReader configReader = new ConfigReader();
+ Config testConfig;
+ try
+ {
+ testConfig = configReader.getConfigFromFile(getCliOptions().get(ControllerRunner.TEST_CONFIG_PROP));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new DistributedTestException("Exception while loading test config", e);
+ }
+ return testConfig;
+ }
+
+ private boolean isDistributed()
+ {
+ return Boolean.valueOf(getCliOptions().get(ControllerRunner.DISTRIBUTED_PROP));
+ }
+
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java
new file mode 100644
index 0000000000..c4892edca9
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java
@@ -0,0 +1,33 @@
+/*
+ * 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.disttest;
+
+public abstract class DistributedTestConstants
+{
+ public static final String PERF_TEST_PROPERTIES_FILE = "perftests.properties";
+
+ public static final String MSG_COMMAND_PROPERTY = "COMMAND";
+ public static final String MSG_JSON_PROPERTY = "JSON";
+
+ public static final long REGISTRATION_TIMEOUT = 60000;
+ public static final long COMMAND_RESPONSE_TIMEOUT = 10000;
+
+ public static final String CONTROLLER_QUEUE_JNDI_NAME = "controllerqueue";
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java
new file mode 100644
index 0000000000..d1d24dcfff
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.disttest;
+
+import org.apache.qpid.disttest.message.Command;
+
+public class DistributedTestException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+ private final Command causeCommand;
+
+ public DistributedTestException(final String message)
+ {
+ this(message, (Command) null);
+ }
+
+ public DistributedTestException(final Throwable cause)
+ {
+ this(cause, null);
+ }
+
+ public DistributedTestException(final String message, final Throwable cause)
+ {
+ this(message, cause, null);
+ }
+
+ public DistributedTestException(final String message, final Command commandCause)
+ {
+ super(message);
+ causeCommand = commandCause;
+ }
+
+ public DistributedTestException(final Throwable cause, final Command commandCause)
+ {
+ super(cause);
+ causeCommand = commandCause;
+ }
+
+ public DistributedTestException(final String message, final Throwable cause, final Command commandCause)
+ {
+ super(message, cause);
+ causeCommand = commandCause;
+ }
+
+ public Command getCauseCommand()
+ {
+ return causeCommand;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java
new file mode 100644
index 0000000000..52dad9aa4d
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.disttest;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A variation of the visitor pattern that uses reflection to call the correct
+ * visit method. By convention, subclasses should provide public
+ * <pre>visit(SpecificClass)</pre> methods.
+ */
+public abstract class Visitor
+{
+
+ private static final String VISITOR_METHOD_NAME = "visit";
+
+ public void visit(Object targetObject)
+ {
+ Class<? extends Object> targetObjectClass = targetObject.getClass();
+ final Method method = findVisitMethodForTargetObjectClass(targetObjectClass);
+ invokeVisitMethod(targetObject, method);
+ }
+
+ private Method findVisitMethodForTargetObjectClass(
+ Class<? extends Object> targetObjectClass)
+ {
+ final Method method;
+ try
+ {
+ method = getClass().getDeclaredMethod(VISITOR_METHOD_NAME, targetObjectClass);
+ }
+ catch (Exception e)
+ {
+ throw new DistributedTestException("Failed to find method " + VISITOR_METHOD_NAME + " on object of class " + targetObjectClass, e);
+ }
+ return method;
+ }
+
+ private void invokeVisitMethod(Object targetObject, final Method method)
+ {
+ try
+ {
+ method.invoke(this, targetObject);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new DistributedTestException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new DistributedTestException(e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new DistributedTestException(e.getCause());
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java
new file mode 100644
index 0000000000..ed29182c51
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java
@@ -0,0 +1,204 @@
+/*
+ * 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.disttest.client;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.naming.NamingException;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.Visitor;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Client
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
+
+ private final ClientJmsDelegate _clientJmsDelegate;
+
+ private final CountDownLatch _latch = new CountDownLatch(1);
+ private Visitor _visitor;
+ private final AtomicReference<ClientState> _state;
+ private ParticipantExecutorRegistry _participantRegistry = new ParticipantExecutorRegistry();
+
+ public Client(final ClientJmsDelegate delegate) throws NamingException
+ {
+ _clientJmsDelegate = delegate;
+ _state = new AtomicReference<ClientState>(ClientState.CREATED);
+ _visitor = new ClientCommandVisitor(this, _clientJmsDelegate);
+ }
+
+ /**
+ * Register with the controller
+ */
+ public void start()
+ {
+ _clientJmsDelegate.setInstructionListener(this);
+ _clientJmsDelegate.sendRegistrationMessage();
+ _state.set(ClientState.READY);
+ }
+
+ public void stop()
+ {
+ _state.set(ClientState.STOPPED);
+ _latch.countDown();
+ }
+
+ public void addParticipantExecutor(final ParticipantExecutor participant)
+ {
+ _participantRegistry.add(participant);
+ }
+
+ public void waitUntilStopped()
+ {
+ waitUntilStopped(0);
+ }
+
+ public void waitUntilStopped(final long timeout)
+ {
+ try
+ {
+ if (timeout == 0)
+ {
+ _latch.await();
+ }
+ else
+ {
+ _latch.await(timeout, TimeUnit.MILLISECONDS);
+ }
+ }
+ catch (final InterruptedException ie)
+ {
+ Thread.currentThread().interrupt();
+ }
+
+ _clientJmsDelegate.destroy();
+ }
+
+ public void processInstruction(final Command command)
+ {
+ String responseMessage = null;
+ try
+ {
+ command.accept(_visitor);
+ }
+ catch (final Exception e)
+ {
+ LOGGER.error("Error processing instruction", e);
+ responseMessage = e.getMessage();
+ }
+ finally
+ {
+ _clientJmsDelegate.sendResponseMessage(new Response(_clientJmsDelegate.getClientName(), command.getType(), responseMessage));
+ }
+ }
+
+ public ClientState getState()
+ {
+ return _state.get();
+ }
+
+ public String getClientName()
+ {
+ return _clientJmsDelegate.getClientName();
+ }
+
+ public void setClientCommandVisitor(final ClientCommandVisitor visitor)
+ {
+ _visitor = visitor;
+ }
+
+ public void startTest()
+ {
+ if (_state.compareAndSet(ClientState.READY, ClientState.RUNNING_TEST))
+ {
+ try
+ {
+ _clientJmsDelegate.startConnections();
+ for (final ParticipantExecutor executor : _participantRegistry.executors())
+ {
+ executor.start(this);
+ }
+ }
+ catch (final Exception e)
+ {
+ try
+ {
+ tearDownTest();
+ }
+ catch (final Exception e2)
+ {
+ // ignore
+ }
+ throw new DistributedTestException("Error starting test: " + _clientJmsDelegate.getClientName(), e);
+ }
+ }
+ else
+ {
+ throw new DistributedTestException("Client '" + _clientJmsDelegate.getClientName()
+ + "' is not in READY state:" + _state.get());
+ }
+ }
+
+ public void tearDownTest()
+ {
+ if (_state.compareAndSet(ClientState.RUNNING_TEST, ClientState.READY))
+ {
+ LOGGER.info("Tearing down test on client: " + _clientJmsDelegate.getClientName());
+
+ _clientJmsDelegate.closeTestConnections();
+ }
+ else
+ {
+ throw new DistributedTestException("Client '" + _clientJmsDelegate.getClientName() + "' is not in RUNNING_TEST state! Ignoring tearDownTest");
+ }
+
+
+ _participantRegistry.clear();
+ }
+
+ public void sendResults(ParticipantResult testResult)
+ {
+ _clientJmsDelegate.sendResponseMessage(testResult);
+ LOGGER.info("Sent test results " + testResult);
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("clientJmsDelegate", _clientJmsDelegate).toString();
+ }
+
+ void setParticipantRegistry(ParticipantExecutorRegistry participantRegistry)
+ {
+ _participantRegistry = participantRegistry;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java
new file mode 100644
index 0000000000..791897323e
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java
@@ -0,0 +1,98 @@
+/*
+ * 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.disttest.client;
+
+import org.apache.qpid.disttest.Visitor;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+
+public class ClientCommandVisitor extends Visitor
+{
+ private final Client _client;
+ private final ClientJmsDelegate _clientJmsDelegate;
+
+ public ClientCommandVisitor(final Client client, final ClientJmsDelegate clientJmsDelegate)
+ {
+ super();
+ _client = client;
+ _clientJmsDelegate = clientJmsDelegate;
+ }
+
+ public void visit(final StopClientCommand command)
+ {
+ _client.stop();
+ }
+
+ public void visit(final NoOpCommand command)
+ {
+ // no-op
+ }
+
+ public void visit(final CreateConnectionCommand command)
+ {
+ _clientJmsDelegate.createConnection(command);
+ }
+
+ public void visit(final CreateSessionCommand command)
+ {
+ _clientJmsDelegate.createSession(command);
+ }
+
+ public void visit(final CreateProducerCommand command)
+ {
+
+ final ProducerParticipant participant = new ProducerParticipant(_clientJmsDelegate, command);
+ _clientJmsDelegate.createProducer(command);
+ final ParticipantExecutor executor = new ParticipantExecutor(participant);
+ _client.addParticipantExecutor(executor);
+ }
+
+ public void visit(final CreateConsumerCommand command)
+ {
+ final ConsumerParticipant participant = new ConsumerParticipant(_clientJmsDelegate, command);
+ _clientJmsDelegate.createConsumer(command);
+ final ParticipantExecutor executor = new ParticipantExecutor(participant);
+ _client.addParticipantExecutor(executor);
+ }
+
+ public void visit(final StartTestCommand command)
+ {
+ _client.startTest();
+ }
+
+ public void visit(final TearDownTestCommand command)
+ {
+ _client.tearDownTest();
+ }
+
+ public void visit(final CreateMessageProviderCommand command)
+ {
+ _clientJmsDelegate.createMessageProvider(command);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java
new file mode 100644
index 0000000000..c88c0a6c86
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java
@@ -0,0 +1,25 @@
+/*
+ * 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.disttest.client;
+
+public enum ClientState
+{
+ CREATED, READY, STOPPED, RUNNING_TEST;
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java
new file mode 100644
index 0000000000..89400b1f72
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java
@@ -0,0 +1,235 @@
+/*
+ * 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.disttest.client;
+
+
+import java.util.Date;
+import java.util.NavigableSet;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConsumerParticipant implements Participant
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerParticipant.class);
+
+ private final AtomicInteger _totalNumberOfMessagesReceived = new AtomicInteger(0);
+ private final NavigableSet<Integer> _allConsumedPayloadSizes = new ConcurrentSkipListSet<Integer>();
+ private final AtomicLong _totalPayloadSizeOfAllMessagesReceived = new AtomicLong(0);
+ private final CountDownLatch _asyncRunHasFinished = new CountDownLatch(1);
+ private final ClientJmsDelegate _jmsDelegate;
+ private final CreateConsumerCommand _command;
+ private final ParticipantResultFactory _resultFactory;
+
+ private long _startTime;
+
+ private volatile Exception _asyncMessageListenerException;
+
+ public ConsumerParticipant(final ClientJmsDelegate delegate, final CreateConsumerCommand command)
+ {
+ _jmsDelegate = delegate;
+ _command = command;
+ _resultFactory = new ParticipantResultFactory();
+ }
+
+ @Override
+ public ParticipantResult doIt(String registeredClientName) throws Exception
+ {
+ final Date start = new Date();
+
+ if (_command.getMaximumDuration() == 0 && _command.getNumberOfMessages() == 0)
+ {
+ throw new DistributedTestException("number of messages and duration cannot both be zero");
+ }
+
+ if (_command.isSynchronous())
+ {
+ synchronousRun();
+ }
+ else
+ {
+ _jmsDelegate.registerListener(_command.getParticipantName(), new MessageListener(){
+
+ @Override
+ public void onMessage(Message message)
+ {
+ processAsynchMessage(message);
+ }
+
+ });
+
+ waitUntilMsgListenerHasFinished();
+ rethrowAnyAsyncMessageListenerException();
+ }
+
+ Date end = new Date();
+ int numberOfMessagesSent = _totalNumberOfMessagesReceived.get();
+ long totalPayloadSize = _totalPayloadSizeOfAllMessagesReceived.get();
+ int payloadSize = getPayloadSizeForResultIfConstantOrZeroOtherwise(_allConsumedPayloadSizes);
+
+ ConsumerParticipantResult result = _resultFactory.createForConsumer(
+ getName(),
+ registeredClientName,
+ _command,
+ numberOfMessagesSent,
+ payloadSize,
+ totalPayloadSize,
+ start,
+ end);
+
+ return result;
+ }
+
+ private void synchronousRun()
+ {
+ LOGGER.debug("entered synchronousRun: " + this);
+
+ _startTime = System.currentTimeMillis();
+
+ Message message = null;
+
+ do
+ {
+ message = _jmsDelegate.consumeMessage(_command.getParticipantName(),
+ _command.getReceiveTimeout());
+ } while (processMessage(message));
+ }
+
+ /**
+ * @return whether to continue running (ie returns false if the message quota has been reached)
+ */
+ private boolean processMessage(Message message)
+ {
+ int messageCount = _totalNumberOfMessagesReceived.incrementAndGet();
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("message " + messageCount + " received by " + this);
+ }
+ int messagePayloadSize = _jmsDelegate.calculatePayloadSizeFrom(message);
+ _allConsumedPayloadSizes.add(messagePayloadSize);
+ _totalPayloadSizeOfAllMessagesReceived.addAndGet(messagePayloadSize);
+
+ boolean batchEnabled = _command.getBatchSize() > 0;
+ boolean batchComplete = batchEnabled && messageCount % _command.getBatchSize() == 0;
+
+ if (!batchEnabled || batchComplete)
+ {
+ _jmsDelegate.commitOrAcknowledgeMessage(message, _command.getSessionName());
+ }
+
+ boolean reachedExpectedNumberOfMessages = _command.getNumberOfMessages() > 0 && messageCount >= _command.getNumberOfMessages();
+ boolean reachedMaximumDuration = _command.getMaximumDuration() > 0 && System.currentTimeMillis() - _startTime >= _command.getMaximumDuration();
+ boolean finishedConsuming = reachedExpectedNumberOfMessages || reachedMaximumDuration;
+
+ if (finishedConsuming)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug("message " + messageCount
+ + " reachedExpectedNumberOfMessages " + reachedExpectedNumberOfMessages
+ + " reachedMaximumDuration " + reachedMaximumDuration);
+ }
+
+ if (batchEnabled && !batchComplete)
+ {
+ // commit/acknowledge remaining messages if necessary
+ _jmsDelegate.commitOrAcknowledgeMessage(message, _command.getSessionName());
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Intended to be called from a {@link MessageListener}. Updates {@link #_asyncRunHasFinished} if
+ * no more messages should be processed, causing {@link #doIt(String)} to exit.
+ */
+ public void processAsynchMessage(Message message)
+ {
+ boolean continueRunning = true;
+ try
+ {
+ if (_startTime == 0)
+ {
+ // reset counter and start time on receiving of first message
+ _startTime = System.currentTimeMillis();
+ }
+
+ continueRunning = processMessage(message);
+ }
+ catch (Exception e)
+ {
+ LOGGER.error("Error occured consuming message " + _totalNumberOfMessagesReceived, e);
+ continueRunning = false;
+ _asyncMessageListenerException = e;
+ }
+
+ if(!continueRunning)
+ {
+ _asyncRunHasFinished.countDown();
+ }
+ }
+
+ @Override
+ public void releaseResources()
+ {
+ _jmsDelegate.closeTestConsumer(_command.getParticipantName());
+ }
+
+ private int getPayloadSizeForResultIfConstantOrZeroOtherwise(NavigableSet<Integer> allSizes)
+ {
+ return allSizes.size() == 1 ? _allConsumedPayloadSizes.first() : 0;
+ }
+
+ private void rethrowAnyAsyncMessageListenerException()
+ {
+ if (_asyncMessageListenerException != null)
+ {
+ throw new DistributedTestException(_asyncMessageListenerException);
+ }
+ }
+
+ private void waitUntilMsgListenerHasFinished() throws Exception
+ {
+ LOGGER.debug("waiting until message listener has finished for " + this);
+ _asyncRunHasFinished.await();
+ LOGGER.debug("Message listener has finished for " + this);
+ }
+
+ @Override
+ public String getName()
+ {
+ return _command.getParticipantName();
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java
new file mode 100644
index 0000000000..2dcf8940b6
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java
@@ -0,0 +1,212 @@
+/*
+ * 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.disttest.client;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+
+public class MessageProvider
+{
+ public static final String TTL = "ttl";
+
+ public static final String DELIVERY_MODE = "deliveryMode";
+
+ public static final String PRIORITY = "priority";
+
+ public static final String[] STANDARD_JMS_PROPERTIES = { "correlationID", DELIVERY_MODE,
+ "expiration", "messageID", PRIORITY, "redelivered", "replyTo", "timestamp", "type", TTL };
+
+ private Map<String, PropertyValue> _messageProperties;
+ private ConcurrentMap<Integer, Future<String>> _payloads;
+
+ public MessageProvider(Map<String, PropertyValue> messageProperties)
+ {
+ _messageProperties = messageProperties;
+ _payloads = new ConcurrentHashMap<Integer, Future<String>>();
+ }
+
+ public Message nextMessage(Session session, CreateProducerCommand command) throws JMSException
+ {
+ Message message = createTextMessage(session, command);
+ setMessageProperties(message);
+ return message;
+ }
+
+ public boolean isPropertySet(String name)
+ {
+ return _messageProperties != null && _messageProperties.containsKey(name);
+ }
+
+ public void setMessageProperties(Message message) throws JMSException
+ {
+ if (_messageProperties != null)
+ {
+ for (Entry<String, PropertyValue> entry : _messageProperties.entrySet())
+ {
+ String propertyName = entry.getKey();
+ Object propertyValue = entry.getValue().getValue();
+ if (isStandardProperty(propertyName))
+ {
+ setStandardProperty(message, propertyName, propertyValue);
+ }
+ else
+ {
+ setCustomProperty(message, propertyName, propertyValue);
+ }
+ }
+ }
+ }
+
+ protected void setCustomProperty(Message message, String propertyName, Object propertyValue) throws JMSException
+ {
+ if (propertyValue instanceof Integer)
+ {
+ message.setIntProperty(propertyName, ((Integer) propertyValue).intValue());
+ }
+ else if (propertyValue instanceof Long)
+ {
+ message.setLongProperty(propertyName, ((Long) propertyValue).longValue());
+ }
+ else if (propertyValue instanceof Boolean)
+ {
+ message.setBooleanProperty(propertyName, ((Boolean) propertyValue).booleanValue());
+ }
+ else if (propertyValue instanceof Byte)
+ {
+ message.setByteProperty(propertyName, ((Byte) propertyValue).byteValue());
+ }
+ else if (propertyValue instanceof Double)
+ {
+ message.setDoubleProperty(propertyName, ((Double) propertyValue).doubleValue());
+ }
+ else if (propertyValue instanceof Float)
+ {
+ message.setFloatProperty(propertyName, ((Float) propertyValue).floatValue());
+ }
+ else if (propertyValue instanceof Short)
+ {
+ message.setShortProperty(propertyName, ((Short) propertyValue).shortValue());
+ }
+ else if (propertyValue instanceof String)
+ {
+ message.setStringProperty(propertyName, (String) propertyValue);
+ }
+ else
+ {
+ message.setObjectProperty(propertyName, propertyValue);
+ }
+ }
+
+ protected void setStandardProperty(Message message, String property, Object propertyValue) throws JMSException
+ {
+ String propertyName = "JMS" + StringUtils.capitalize(property);
+ try
+ {
+ BeanUtils.setProperty(message, propertyName, propertyValue);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new DistributedTestException("Unable to set property " + propertyName + " :" + e.getMessage(), e);
+ }
+ catch (InvocationTargetException e)
+ {
+ if (e.getCause() instanceof JMSException)
+ {
+ throw ((JMSException) e.getCause());
+ }
+ else
+ {
+ throw new DistributedTestException("Unable to set property " + propertyName + " :" + e.getMessage(), e);
+ }
+ }
+ }
+
+ protected boolean isStandardProperty(String propertyName)
+ {
+ for (int i = 0; i < STANDARD_JMS_PROPERTIES.length; i++)
+ {
+ if (propertyName.equals(STANDARD_JMS_PROPERTIES[i]))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected Message createTextMessage(Session ssn, final CreateProducerCommand command) throws JMSException
+ {
+ String payload = getMessagePayload(command);
+ TextMessage msg = ssn.createTextMessage();
+ msg.setText(payload);
+ return msg;
+ }
+
+ protected String getMessagePayload(final CreateProducerCommand command)
+ {
+ FutureTask<String> createTextFuture = new FutureTask<String>(new Callable<String>()
+ {
+ @Override
+ public String call() throws Exception
+ {
+ return StringUtils.repeat("a", command.getMessageSize());
+ }
+ });
+
+ Future<String> future = _payloads.putIfAbsent(command.getMessageSize(), createTextFuture);
+ if (future == null)
+ {
+ createTextFuture.run();
+ future = createTextFuture;
+ }
+ String payload = null;
+ try
+ {
+ payload = future.get();
+ }
+ catch (Exception e)
+ {
+ throw new DistributedTestException("Unable to create message payload :" + e.getMessage(), e);
+ }
+ return payload;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "MessageProvider [_messageProperties=" + _messageProperties + "]";
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java
new file mode 100644
index 0000000000..941ec90565
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java
@@ -0,0 +1,31 @@
+/*
+ * 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.disttest.client;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+
+public interface Participant
+{
+ ParticipantResult doIt(String registeredClientName) throws Exception;
+
+ void releaseResources();
+
+ String getName();
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java
new file mode 100644
index 0000000000..dee1391868
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java
@@ -0,0 +1,132 @@
+/*
+ * 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.disttest.client;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ParticipantExecutor
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantExecutor.class);
+
+ private static final ExecutorService SHARED_UNBOUNDED_THREAD_POOL = Executors.newCachedThreadPool(new DaemonThreadFactory());
+
+ private Executor _executor = SHARED_UNBOUNDED_THREAD_POOL;
+
+ private Client _client;
+
+ private final Participant _participant;
+
+ private final ParticipantResultFactory _factory;
+
+ public ParticipantExecutor(Participant participant)
+ {
+ _participant = participant;
+ _factory = new ParticipantResultFactory();
+ }
+
+ /**
+ * Schedules the test participant to be run in a background thread.
+ */
+ public void start(Client client)
+ {
+ _client = client;
+
+ LOGGER.info("Starting test participant in background thread: " + this);
+ _executor.execute(new ParticipantRunnable());
+ }
+
+ public String getParticipantName()
+ {
+ return _participant.getName();
+ }
+
+ void setExecutor(Executor executor)
+ {
+ _executor = executor;
+ }
+
+ private class ParticipantRunnable implements Runnable
+ {
+ @Override
+ public final void run()
+ {
+ Thread currentThread = Thread.currentThread();
+ final String initialThreadName = currentThread.getName();
+ currentThread.setName(initialThreadName + "-" + getParticipantName());
+
+ try
+ {
+ runParticipantAndSendResults();
+ }
+ finally
+ {
+ currentThread.setName(initialThreadName);
+ }
+ }
+
+ private void runParticipantAndSendResults()
+ {
+ ParticipantResult result = null;
+ try
+ {
+ result = _participant.doIt(_client.getClientName());
+ }
+ catch (Throwable t)
+ {
+ String errorMessage = "Unhandled error: " + t.getMessage();
+ LOGGER.error(errorMessage, t);
+ result = _factory.createForError(_participant.getName(), _client.getClientName(), errorMessage);
+ }
+ finally
+ {
+ _client.sendResults(result);
+ _participant.releaseResources();
+ }
+ }
+ }
+
+ private static final class DaemonThreadFactory implements ThreadFactory
+ {
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ Thread thread = new Thread(r);
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("participantName", getParticipantName())
+ .append("client", _client)
+ .toString();
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java
new file mode 100644
index 0000000000..3d9780e640
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java
@@ -0,0 +1,45 @@
+/*
+ * 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.disttest.client;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ParticipantExecutorRegistry
+{
+ private final Set<ParticipantExecutor> _participantExecutors = Collections.synchronizedSet(new HashSet<ParticipantExecutor>());
+
+ public void add(ParticipantExecutor participantExecutor)
+ {
+ _participantExecutors.add(participantExecutor);
+ }
+
+ public void clear()
+ {
+ _participantExecutors.clear();
+ }
+
+ public Collection<ParticipantExecutor> executors()
+ {
+ return Collections.unmodifiableSet(_participantExecutors);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java
new file mode 100644
index 0000000000..61b64b8c4f
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java
@@ -0,0 +1,94 @@
+/*
+ * 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.disttest.client;
+
+import java.util.Date;
+
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateParticpantCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+
+public class ParticipantResultFactory
+{
+ public ConsumerParticipantResult createForConsumer(String participantName, String clientRegisteredName, CreateConsumerCommand command, int numberOfMessagesReceived, int payloadSize, long totalPayloadReceived, Date start, Date end)
+ {
+ ConsumerParticipantResult consumerParticipantResult = new ConsumerParticipantResult();
+
+ setTestProperties(consumerParticipantResult, command, participantName, clientRegisteredName);
+ setTestResultProperties(consumerParticipantResult, numberOfMessagesReceived, payloadSize, totalPayloadReceived, start, end);
+
+ consumerParticipantResult.setTopic(command.isTopic());
+ consumerParticipantResult.setDurableSubscription(command.isDurableSubscription());
+ consumerParticipantResult.setBrowsingSubscription(command.isBrowsingSubscription());
+ consumerParticipantResult.setSelector(command.getSelector() != null);
+ consumerParticipantResult.setNoLocal(command.isNoLocal());
+ consumerParticipantResult.setSynchronousConsumer(command.isSynchronous());
+
+ return consumerParticipantResult;
+ }
+
+ public ProducerParticipantResult createForProducer(String participantName, String clientRegisteredName, CreateProducerCommand command, int numberOfMessagesSent, int payloadSize, long totalPayloadSent, Date start, Date end)
+ {
+ final ProducerParticipantResult participantResult = new ProducerParticipantResult();
+
+ participantResult.setStartDelay(command.getStartDelay());
+ participantResult.setDeliveryMode(command.getDeliveryMode());
+ participantResult.setPriority(command.getPriority());
+ participantResult.setInterval(command.getInterval());
+ participantResult.setTimeToLive(command.getTimeToLive());
+
+ setTestProperties(participantResult, command, participantName, clientRegisteredName);
+
+ setTestResultProperties(participantResult, numberOfMessagesSent, payloadSize, totalPayloadSent, start, end);
+
+ return participantResult;
+ }
+
+ private void setTestResultProperties(final ParticipantResult participantResult, int numberOfMessagesSent, int payloadSize, long totalPayloadReceived, Date start, Date end)
+ {
+ participantResult.setNumberOfMessagesProcessed(numberOfMessagesSent);
+ participantResult.setPayloadSize(payloadSize);
+ participantResult.setTotalPayloadProcessed(totalPayloadReceived);
+ participantResult.setStartDate(start);
+ participantResult.setEndDate(end);
+ }
+
+ private void setTestProperties(final ParticipantResult participantResult, CreateParticpantCommand command, String participantName, String clientRegisteredName)
+ {
+ participantResult.setParticipantName(participantName);
+ participantResult.setRegisteredClientName(clientRegisteredName);
+ participantResult.setBatchSize(command.getBatchSize());
+ participantResult.setMaximumDuration(command.getMaximumDuration());
+
+ }
+
+ public ParticipantResult createForError(String participantName, String clientRegisteredName, String errorMessage)
+ {
+ ParticipantResult result = new ParticipantResult();
+ result.setParticipantName(participantName);
+ result.setRegisteredClientName(clientRegisteredName);
+ result.setErrorMessage(errorMessage);
+
+ return result;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java
new file mode 100644
index 0000000000..a46794f380
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java
@@ -0,0 +1,158 @@
+/*
+ * 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.disttest.client;
+
+import java.util.Date;
+import java.util.NavigableSet;
+import java.util.TreeSet;
+
+import javax.jms.Message;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProducerParticipant implements Participant
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProducerParticipant.class);
+
+ private final ClientJmsDelegate _jmsDelegate;
+
+ private final CreateProducerCommand _command;
+
+ private ParticipantResultFactory _resultFactory;
+
+ public ProducerParticipant(final ClientJmsDelegate jmsDelegate, final CreateProducerCommand command)
+ {
+ _jmsDelegate = jmsDelegate;
+ _command = command;
+ _resultFactory = new ParticipantResultFactory();
+ }
+
+ @Override
+ public ParticipantResult doIt(String registeredClientName) throws Exception
+ {
+ if (_command.getMaximumDuration() == 0 && _command.getNumberOfMessages() == 0)
+ {
+ throw new DistributedTestException("number of messages and duration cannot both be zero");
+ }
+
+ long expectedDuration = _command.getMaximumDuration() - _command.getStartDelay();
+
+ doSleepForStartDelay();
+
+ final long startTime = System.currentTimeMillis();
+
+ Message lastPublishedMessage = null;
+ int numberOfMessagesSent = 0;
+ long totalPayloadSizeOfAllMessagesSent = 0;
+ NavigableSet<Integer> allProducedPayloadSizes = new TreeSet<Integer>();
+
+ while (true)
+ {
+ numberOfMessagesSent++;
+
+ lastPublishedMessage = _jmsDelegate.sendNextMessage(_command);
+
+ int lastPayloadSize = _jmsDelegate.calculatePayloadSizeFrom(lastPublishedMessage);
+ totalPayloadSizeOfAllMessagesSent += lastPayloadSize;
+ allProducedPayloadSizes.add(lastPayloadSize);
+
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("message " + numberOfMessagesSent + " sent by " + this);
+ }
+
+ final boolean batchLimitReached = _command.getBatchSize() <= 0
+ || numberOfMessagesSent % _command.getBatchSize() == 0;
+
+ if (batchLimitReached)
+ {
+ _jmsDelegate.commitOrAcknowledgeMessage(lastPublishedMessage, _command.getSessionName());
+
+ if (_command.getInterval() > 0)
+ {
+ // sleep for given time
+ Thread.sleep(_command.getInterval());
+ }
+ }
+
+ if (_command.getNumberOfMessages() > 0 && numberOfMessagesSent >= _command.getNumberOfMessages()
+ || expectedDuration > 0 && System.currentTimeMillis() - startTime >= expectedDuration)
+ {
+ break;
+ }
+ }
+
+ // commit the remaining batch messages
+ if (_command.getBatchSize() > 0 && numberOfMessagesSent % _command.getBatchSize() != 0)
+ {
+ _jmsDelegate.commitOrAcknowledgeMessage(lastPublishedMessage, _command.getSessionName());
+ }
+
+ Date start = new Date(startTime);
+ Date end = new Date();
+ int payloadSize = getPayloadSizeForResultIfConstantOrZeroOtherwise(allProducedPayloadSizes);
+
+ return _resultFactory.createForProducer(
+ getName(),
+ registeredClientName,
+ _command,
+ numberOfMessagesSent,
+ payloadSize,
+ totalPayloadSizeOfAllMessagesSent, start, end);
+ }
+
+ private int getPayloadSizeForResultIfConstantOrZeroOtherwise(NavigableSet<Integer> allPayloadSizes)
+ {
+ return allPayloadSizes.size() == 1 ? allPayloadSizes.first() : 0;
+ }
+
+ private void doSleepForStartDelay()
+ {
+ if (_command.getStartDelay() > 0)
+ {
+ // start delay is specified. Sleeping...
+ try
+ {
+ Thread.sleep(_command.getStartDelay());
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ @Override
+ public void releaseResources()
+ {
+ _jmsDelegate.closeTestProducer(_command.getParticipantName());
+ }
+
+ @Override
+ public String getName()
+ {
+ return _command.getParticipantName();
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java
new file mode 100644
index 0000000000..a49ebf756e
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java
@@ -0,0 +1,68 @@
+/*
+ * 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.disttest.client.property;
+
+/**
+ * Provides support to generate message property values.
+ */
+public abstract class GeneratedPropertySupport implements GeneratedPropertyValue
+{
+ private Object _lastValue;
+
+ public GeneratedPropertySupport()
+ {
+ super();
+ _lastValue = null;
+ }
+
+ @Override
+ public Object getValue()
+ {
+ Object result = nextValue();
+ result = evaluate(result);
+ synchronized(this)
+ {
+ _lastValue = result;
+ }
+ return result;
+ }
+
+ protected Object evaluate(Object result)
+ {
+ while (result instanceof PropertyValue)
+ {
+ result = ((PropertyValue)result).getValue();
+ }
+ return result;
+ }
+
+ public abstract Object nextValue();
+
+ public synchronized Object getLastValue()
+ {
+ return _lastValue;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "GeneratedPropertyValue [value=" + getLastValue() + ", @def=" + getDefinition() + "]";
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java
new file mode 100644
index 0000000000..39c093fac5
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java
@@ -0,0 +1,27 @@
+/*
+ * 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.disttest.client.property;
+
+/**
+ * Provides operations to generate message property values.
+ */
+public interface GeneratedPropertyValue extends PropertyValue
+{
+ public String getDefinition();
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java
new file mode 100644
index 0000000000..4444351976
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java
@@ -0,0 +1,122 @@
+/*
+ * 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.disttest.client.property;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Provides property values from the underlining list of items.
+ */
+public class ListPropertyValue extends GeneratedPropertySupport
+{
+ public static final String DEF_VALUE = "list";
+ private List<PropertyValue> _items;
+ private boolean _cyclic;
+ private int _currentIndex;
+
+ public ListPropertyValue()
+ {
+ super();
+ _cyclic = true;
+ _currentIndex = 0;
+ _items = new ArrayList<PropertyValue>();
+ }
+
+ public synchronized void setItems(List<PropertyValue> items)
+ {
+ _items = new ArrayList<PropertyValue>(items);
+ }
+
+ public synchronized List<PropertyValue> getItems()
+ {
+ return Collections.unmodifiableList(_items);
+ }
+
+ public synchronized void setCyclic(boolean cyclic)
+ {
+ _cyclic = cyclic;
+ }
+
+ public synchronized boolean isCyclic()
+ {
+ return _cyclic;
+ }
+
+ @Override
+ public synchronized Object nextValue()
+ {
+ if (_currentIndex >= _items.size())
+ {
+ if (_cyclic)
+ {
+ _currentIndex = 0;
+ }
+ else
+ {
+ _currentIndex = _items.size() -1;
+ }
+ }
+ Object nextValue = _items.get(_currentIndex);
+ _currentIndex++;
+ return nextValue;
+ }
+
+ @Override
+ public String getDefinition()
+ {
+ return DEF_VALUE;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + _currentIndex;
+ result = prime * result + (_cyclic ? 1231 : 1237);
+ result = prime * result + ((_items == null) ? 0 : _items.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null || !(obj instanceof ListPropertyValue))
+ {
+ return false;
+ }
+ ListPropertyValue other = (ListPropertyValue) obj;
+ if (_cyclic != other._cyclic)
+ {
+ return false;
+ }
+ if (_items == null && other._items != null)
+ {
+ return false;
+ }
+ return _items.equals(other._items);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java
new file mode 100644
index 0000000000..e0ae137c35
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java
@@ -0,0 +1,179 @@
+/*
+ * 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.disttest.client.property;
+
+import java.util.Arrays;
+
+/**
+ * Provides support for numeric generators with lower and upper boundaries.
+ */
+public abstract class NumericGeneratedPropertySupport extends GeneratedPropertySupport
+{
+ public static final Class<?>[] SUPPORTED_TYPES = { double.class, float.class, int.class, long.class, short.class,
+ byte.class };
+
+ private String _type;
+ private double _upper;
+ private double _lower;
+
+
+ public NumericGeneratedPropertySupport()
+ {
+ super();
+ _type = SUPPORTED_TYPES[0].getName();
+ _upper = Double.MAX_VALUE;
+ _lower = 0.0;
+ }
+
+ public synchronized String getType()
+ {
+ return _type;
+ }
+
+ public synchronized double getUpper()
+ {
+ return _upper;
+ }
+
+ public synchronized double getLower()
+ {
+ return _lower;
+ }
+
+ public synchronized void setUpper(double upper)
+ {
+ _upper = upper;
+ }
+
+ public synchronized void setLower(double lower)
+ {
+ _lower = lower;
+ }
+
+ public synchronized void setType(String type)
+ {
+ _type = toClass(type).getName();
+ }
+
+ protected Class<?> toClass(String type)
+ {
+ Class<?> t = null;
+ for (int i = 0; i < SUPPORTED_TYPES.length; i++)
+ {
+ if (SUPPORTED_TYPES[i].getName().equals(type))
+ {
+ t = SUPPORTED_TYPES[i];
+ break;
+ }
+ }
+ if (t == null)
+ {
+ throw new IllegalArgumentException("Type " + type + " is not supported: "
+ + Arrays.toString(SUPPORTED_TYPES));
+ }
+ return t;
+ }
+
+ @Override
+ public Object nextValue()
+ {
+ double result = nextDouble();
+ return doubleToNumber(result, toClass(_type));
+ }
+
+ protected Number doubleToNumber(double value, Class<?> targetType)
+ {
+ Number result = null;
+ if (targetType == double.class)
+ {
+ result = new Double(value);
+ }
+ else if (targetType == float.class)
+ {
+ result = new Float(value);
+ }
+ else if (targetType == int.class)
+ {
+ result = new Integer((int) value);
+ }
+ else if (targetType == long.class)
+ {
+ result = new Long((long) value);
+ }
+ else if (targetType == short.class)
+ {
+ result = new Short((short) value);
+ }
+ else if (targetType == byte.class)
+ {
+ result = new Byte((byte) value);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Type " + targetType + " is not supported: "
+ + Arrays.toString(SUPPORTED_TYPES));
+ }
+ return result;
+ }
+
+ protected abstract double nextDouble();
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ long temp;
+ temp = Double.doubleToLongBits(_lower);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ result = prime * result + ((_type == null) ? 0 : _type.hashCode());
+ temp = Double.doubleToLongBits(_upper);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null || !(obj instanceof NumericGeneratedPropertySupport))
+ {
+ return false;
+ }
+ NumericGeneratedPropertySupport other = (NumericGeneratedPropertySupport) obj;
+ if (Double.doubleToLongBits(_lower) != Double.doubleToLongBits(other._lower)
+ || Double.doubleToLongBits(_upper) != Double.doubleToLongBits(other._upper))
+ {
+ return false;
+ }
+ if (_type == null && other._type != null)
+ {
+ return false;
+ }
+ else if (!_type.equals(other._type))
+ {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java
new file mode 100644
index 0000000000..97adc0cee1
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java
@@ -0,0 +1,27 @@
+/*
+ * 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.disttest.client.property;
+
+/**
+ * Provides operations to get a message property value.
+ */
+public interface PropertyValue
+{
+ public Object getValue();
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java
new file mode 100644
index 0000000000..fa44b2da1e
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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.disttest.client.property;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.disttest.DistributedTestException;
+
+/**
+ * Creates property value instances using given alias (type) value.
+ */
+public class PropertyValueFactory
+{
+ public PropertyValue createPropertyValue(String type)
+ {
+ try
+ {
+ return (PropertyValue)getPropertyValueClass(type).newInstance();
+ }
+ catch(Exception e)
+ {
+ throw new DistributedTestException("Unable to create a generator for a type:" + type, e);
+ }
+ }
+
+ public Class<?> getPropertyValueClass(String type) throws ClassNotFoundException
+ {
+ String className = "org.apache.qpid.disttest.client.property." + StringUtils.capitalize(type) + "PropertyValue";
+ return Class.forName(className);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java
new file mode 100644
index 0000000000..4f44a4bca8
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java
@@ -0,0 +1,47 @@
+/*
+ * 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.disttest.client.property;
+
+/**
+ * Generates random property values in a given lower and upper boundaries.
+ */
+public class RandomPropertyValue extends NumericGeneratedPropertySupport
+{
+ public static final String DEF_VALUE = "random";
+
+ public RandomPropertyValue()
+ {
+ super();
+ }
+
+ @Override
+ protected double nextDouble()
+ {
+ double lower = getLower();
+ double upper = getUpper();
+ return lower + Math.random() * (upper - lower);
+ }
+
+ @Override
+ public String getDefinition()
+ {
+ return DEF_VALUE;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java
new file mode 100644
index 0000000000..3aca4d4bca
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java
@@ -0,0 +1,129 @@
+/*
+ * 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.disttest.client.property;
+
+/**
+ * Generates property values from a range with given lower and upper boundaries.
+ */
+public class RangePropertyValue extends NumericGeneratedPropertySupport
+{
+ public static final String DEF_VALUE = "range";
+ private double _step;
+ private double _currentValue;
+ private boolean _cyclic;
+
+ public RangePropertyValue()
+ {
+ super();
+ _cyclic = true;
+ _currentValue = 0.0;
+ _step = 1.0;
+ }
+
+ public synchronized double getStep()
+ {
+ return _step;
+ }
+
+ public synchronized boolean isCyclic()
+ {
+ return _cyclic;
+ }
+
+ public synchronized void setCyclic(boolean cyclic)
+ {
+ _cyclic = cyclic;
+ }
+
+ public synchronized void setStep(double step)
+ {
+ _step = step;
+ }
+
+ @Override
+ public synchronized double nextDouble()
+ {
+ double result = 0.0;
+ double lower = getLower();
+ double upper = getUpper();
+ if (_currentValue < lower)
+ {
+ _currentValue = lower;
+ }
+ else if (_currentValue > upper)
+ {
+ if (_cyclic)
+ {
+ _currentValue = lower;
+ }
+ else
+ {
+ _currentValue = upper;
+ }
+ }
+ result = _currentValue;
+ _currentValue += _step;
+ return result;
+ }
+
+ @Override
+ public String getDefinition()
+ {
+ return DEF_VALUE;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ long temp;
+ temp = Double.doubleToLongBits(_currentValue);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ result = prime * result + (_cyclic ? 1231 : 1237);
+ temp = Double.doubleToLongBits(_step);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (!(obj instanceof RangePropertyValue))
+ {
+ return false;
+ }
+ if (!super.equals(obj))
+ {
+ return false;
+ }
+ RangePropertyValue other = (RangePropertyValue) obj;
+ if (Double.doubleToLongBits(_currentValue) != Double.doubleToLongBits(other._currentValue)
+ || Double.doubleToLongBits(_step) != Double.doubleToLongBits(other._step) || _cyclic != other._cyclic)
+ {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java
new file mode 100644
index 0000000000..9141e68656
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.client.property;
+
+/**
+ * Simple property value holder for a constant properties.
+ */
+public class SimplePropertyValue implements PropertyValue
+{
+ private Object _value;
+
+ public SimplePropertyValue()
+ {
+ super();
+ }
+
+ public SimplePropertyValue(Object value)
+ {
+ super();
+ this._value = value;
+ }
+
+ @Override
+ public Object getValue()
+ {
+ return _value;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "SimplePropertyValue [value=" + _value + "]";
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_value == null) ? 0 : _value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass())
+ {
+ return false;
+ }
+ SimplePropertyValue other = (SimplePropertyValue) obj;
+ if (_value == null && other._value != null)
+ {
+ return false;
+ }
+ return _value.equals(other._value);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java
new file mode 100644
index 0000000000..b049da1f84
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.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.disttest.controller;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientRegistry
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ClientRegistry.class);
+
+ private final Set<String> _registeredClientNames = new ConcurrentSkipListSet<String>();
+
+ public void registerClient(String clientName)
+ {
+ final boolean alreadyContainsClient = !_registeredClientNames.add(clientName);
+ if (alreadyContainsClient)
+ {
+ throw new DistributedTestException("Duplicate client name " + clientName);
+ }
+
+ LOGGER.info("Client registered: " + clientName);
+ }
+
+ public Collection<String> getClients()
+ {
+ return Collections.unmodifiableSet(_registeredClientNames);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java
new file mode 100644
index 0000000000..6c0c253807
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java
@@ -0,0 +1,46 @@
+/*
+ * 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.disttest.controller;
+
+import org.apache.qpid.disttest.message.Command;
+
+public class CommandForClient
+{
+ private String _clientName;
+ private Command _command;
+
+ public CommandForClient(String clientName, Command command)
+ {
+ _clientName = clientName;
+ _command = command;
+ }
+
+ public String getClientName()
+ {
+ return _clientName;
+ }
+
+ public Command getCommand()
+ {
+ return _command;
+ }
+
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java
new file mode 100644
index 0000000000..e2f40bebe8
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.disttest.controller;
+
+import org.apache.qpid.disttest.message.Command;
+
+public interface CommandListener
+{
+
+ public abstract void processCommand(Command command);
+
+ public boolean supports(Command command);
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java
new file mode 100644
index 0000000000..a5e0933704
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java
@@ -0,0 +1,227 @@
+/*
+ * 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.disttest.controller;
+
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.controller.config.TestInstance;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Controller
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(Controller.class);
+
+ private final long _registrationTimeout;
+ private final long _commandResponseTimeout;
+
+ private final ControllerJmsDelegate _jmsDelegate;
+
+ private volatile CountDownLatch _clientRegistrationLatch;
+ private volatile CountDownLatch _stopClientsResponseLatch = null;
+
+ private Config _config;
+ private TestRunnerFactory _testRunnerFactory;
+ private ClientRegistry _clientRegistry;
+
+ private long _testResultTimeout = TestRunner.WAIT_FOREVER;
+
+ public Controller(final ControllerJmsDelegate jmsDelegate, long registrationTimeout, long commandResponseTimeout)
+ {
+ _jmsDelegate = jmsDelegate;
+ _registrationTimeout = registrationTimeout;
+ _commandResponseTimeout = commandResponseTimeout;
+ _testRunnerFactory = new TestRunnerFactory();
+ _clientRegistry = new ClientRegistry();
+ }
+
+ public void setConfig(Config config)
+ {
+ _config = config;
+ validateConfiguration();
+ int numberOfClients = config.getTotalNumberOfClients();
+ _clientRegistrationLatch = new CountDownLatch(numberOfClients);
+
+ _jmsDelegate.addCommandListener(new RegisterClientCommandListener());
+ _jmsDelegate.addCommandListener(new StopClientResponseListener());
+ _jmsDelegate.start();
+ }
+
+
+ public void awaitClientRegistrations()
+ {
+ LOGGER.info("Awaiting client registration");
+ awaitLatch(_clientRegistrationLatch, _registrationTimeout, "Timed out waiting for registrations. Expecting %d more registrations");
+ }
+
+ private void validateConfiguration()
+ {
+ if (_config == null || _config.getTotalNumberOfClients() == 0)
+ {
+ throw new DistributedTestException("No controller config or no clients specified in test config");
+ }
+ }
+
+ private void awaitLatch(CountDownLatch latch, long timeout, String messageWithOneDecimalPlaceholder)
+ {
+ try
+ {
+ final boolean countedDownOK = latch.await(timeout, TimeUnit.MILLISECONDS);
+ if (!countedDownOK)
+ {
+ final long latchCount = latch.getCount();
+ String formattedMessage = String.format(messageWithOneDecimalPlaceholder, latchCount);
+ throw new DistributedTestException(formattedMessage);
+ }
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public void registerClient(final RegisterClientCommand registrationCommand)
+ {
+ final String clientName = registrationCommand.getClientName();
+
+ _clientRegistry.registerClient(clientName);
+ _jmsDelegate.registerClient(registrationCommand);
+
+ _clientRegistrationLatch.countDown();
+ LOGGER.info("Counted down latch for client: " + clientName + " latch count=" + _clientRegistrationLatch.getCount());
+ }
+
+ void processStopClientResponse(final Response response)
+ {
+ _stopClientsResponseLatch.countDown();
+ if (response.hasError())
+ {
+ LOGGER.error("Client " + response.getRegisteredClientName() + " reported exception in response to command : " +
+ response.getErrorMessage());
+ }
+ }
+
+ public void stopAllRegisteredClients()
+ {
+ Collection<String> registeredClients = _clientRegistry.getClients();
+
+ LOGGER.info("Stopping all clients");
+ _stopClientsResponseLatch = new CountDownLatch(registeredClients.size());
+ Command command = new StopClientCommand();
+ for (final String clientName : registeredClients)
+ {
+ _jmsDelegate.sendCommandToClient(clientName, command);
+ }
+
+ awaitLatch(_stopClientsResponseLatch, _commandResponseTimeout, "Timed out waiting for stop command responses. Expecting %d more responses.");
+
+ LOGGER.info("Stopped all clients");
+ }
+
+
+ public ResultsForAllTests runAllTests()
+ {
+ LOGGER.info("Running all tests");
+
+ ResultsForAllTests resultsForAllTests = new ResultsForAllTests();
+
+ for (TestInstance testInstance : _config.getTests())
+ {
+
+ ParticipatingClients participatingClients = new ParticipatingClients(_clientRegistry, testInstance.getClientNames());
+
+ LOGGER.info("Running test " + testInstance + ". Participating clients: " + participatingClients.getRegisteredNames());
+ TestRunner runner = _testRunnerFactory.createTestRunner(participatingClients,
+ testInstance,
+ _jmsDelegate,
+ _commandResponseTimeout,
+ _testResultTimeout);
+
+ TestResult testResult = runner.run();
+ LOGGER.info("Finished test " + testInstance);
+
+ resultsForAllTests.add(testResult);
+ }
+
+ return resultsForAllTests;
+ }
+
+ private final class StopClientResponseListener implements CommandListener
+ {
+ @Override
+ public boolean supports(Command command)
+ {
+ return command.getType() == CommandType.RESPONSE && ((Response)command).getInReplyToCommandType() == CommandType.STOP_CLIENT;
+ }
+
+ @Override
+ public void processCommand(Command command)
+ {
+ processStopClientResponse((Response)command);
+ }
+ }
+
+ private final class RegisterClientCommandListener implements
+ CommandListener
+ {
+ @Override
+ public boolean supports(Command command)
+ {
+ return command.getType() == CommandType.REGISTER_CLIENT;
+ }
+
+ @Override
+ public void processCommand(Command command)
+ {
+ registerClient((RegisterClientCommand)command);
+ }
+ }
+
+ public void setTestResultTimeout(final long testResultTimeout)
+ {
+ _testResultTimeout = testResultTimeout;
+
+ }
+
+ void setClientRegistry(ClientRegistry clientRegistry)
+ {
+ _clientRegistry = clientRegistry;
+
+ }
+
+ void setTestRunnerFactory(TestRunnerFactory factory)
+ {
+ if (factory == null)
+ {
+ throw new IllegalArgumentException("TestRunnerFactory cannot be null!");
+ }
+ _testRunnerFactory = factory;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java
new file mode 100644
index 0000000000..077d628697
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java
@@ -0,0 +1,94 @@
+/*
+ * 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.disttest.controller;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.apache.commons.collections.BidiMap;
+import org.apache.commons.collections.bidimap.DualHashBidiMap;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+public class ParticipatingClients
+{
+ private final BidiMap _configuredToRegisteredNameMap;
+
+ public ParticipatingClients(ClientRegistry clientRegistry, List<String> configuredClientNamesForTest)
+ {
+ _configuredToRegisteredNameMap = mapConfiguredToRegisteredClientNames(configuredClientNamesForTest, clientRegistry);
+ }
+
+ public String getRegisteredNameFromConfiguredName(String clientConfiguredName)
+ {
+ String registeredClientName = (String) _configuredToRegisteredNameMap.get(clientConfiguredName);
+ if (registeredClientName == null)
+ {
+ throw new IllegalArgumentException("Unrecognised client configured name " + clientConfiguredName
+ + " Mapping is " + _configuredToRegisteredNameMap);
+ }
+ return registeredClientName;
+ }
+
+ public String getConfiguredNameFromRegisteredName(String registeredClientName)
+ {
+ String clientConfiguredName = (String) _configuredToRegisteredNameMap.getKey(registeredClientName);
+ if (clientConfiguredName == null)
+ {
+ throw new IllegalArgumentException("Unrecognised client registered name " + registeredClientName
+ + " Mapping is " + _configuredToRegisteredNameMap);
+ }
+
+ return clientConfiguredName;
+ }
+
+ private BidiMap mapConfiguredToRegisteredClientNames(List<String> configuredClientNamesForTest, ClientRegistry clientRegistry)
+ {
+ BidiMap configuredToRegisteredNameMap = new DualHashBidiMap();
+
+ TreeSet<String> registeredClients = new TreeSet<String>(clientRegistry.getClients());
+ for (String configuredClientName : configuredClientNamesForTest)
+ {
+ String allocatedClientName = registeredClients.pollFirst();
+ if (allocatedClientName == null)
+ {
+ throw new IllegalArgumentException("Too few clients in registry " + clientRegistry + " configured clients " + configuredClientNamesForTest);
+ }
+ configuredToRegisteredNameMap.put(configuredClientName, allocatedClientName);
+ }
+
+ return configuredToRegisteredNameMap;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection<String> getRegisteredNames()
+ {
+ return _configuredToRegisteredNameMap.values();
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("configuredToRegisteredNameMap", _configuredToRegisteredNameMap).toString();
+ }
+
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java
new file mode 100644
index 0000000000..6c5ff3450c
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
+
+public class ResultsForAllTests
+{
+ private List<ITestResult> _results = new ArrayList<ITestResult>();
+ private boolean _hasErrors;
+
+ public List<ITestResult> getTestResults()
+ {
+ return _results;
+ }
+
+ public void add(ITestResult testResult)
+ {
+ _results.add(testResult);
+ if(testResult.hasErrors())
+ {
+ _hasErrors = true;
+ }
+ }
+
+ public boolean hasErrors()
+ {
+ return _hasErrors;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java
new file mode 100644
index 0000000000..756c641532
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java
@@ -0,0 +1,70 @@
+/*
+ * 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.disttest.controller;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
+
+public class TestResult implements ITestResult
+{
+ private final SortedSet<ParticipantResult> _participantResults = Collections.synchronizedSortedSet(
+ new TreeSet<ParticipantResult>(ParticipantResult.PARTICIPANT_NAME_COMPARATOR));
+
+ private boolean _hasErrors;
+ private String _name;
+
+ public TestResult(String name)
+ {
+ _name = name;
+ }
+
+ @Override
+ public List<ParticipantResult> getParticipantResults()
+ {
+ List<ParticipantResult> list = new ArrayList<ParticipantResult>(_participantResults);
+ return Collections.unmodifiableList(list);
+ }
+
+ public void addParticipantResult(ParticipantResult participantResult)
+ {
+ _participantResults.add(participantResult);
+ if(participantResult.hasError())
+ {
+ _hasErrors = true;
+ }
+ }
+
+ @Override
+ public boolean hasErrors()
+ {
+ return _hasErrors;
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java
new file mode 100644
index 0000000000..f81b691ea6
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java
@@ -0,0 +1,307 @@
+/*
+ * 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.disttest.controller;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+import org.apache.qpid.disttest.controller.config.TestInstance;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestRunner
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(TestRunner.class);
+
+ private static final long PARTICIPANT_RESULTS_LOG_INTERVAL = 60000;
+ public static final long WAIT_FOREVER = -1;
+
+ private final long _commandResponseTimeout;
+
+ private final Set<CommandType> _setOfResponsesToExpect = Collections.synchronizedSet(new HashSet<CommandType>());
+
+ private final ParticipatingClients _participatingClients;
+
+ private final TestInstance _testInstance;
+ private ControllerJmsDelegate _jmsDelegate;
+
+ private volatile CountDownLatch _commandResponseLatch = null;
+ private final CountDownLatch _testResultsLatch;
+ private final TestResult _testResult;
+
+ /** Length of time to await test results or {@value #WAIT_FOREVER} */
+ private final long _testResultTimeout;
+
+
+ public TestRunner(ParticipatingClients participatingClients, TestInstance testInstance, ControllerJmsDelegate jmsDelegate, long commandResponseTimeout, long testResultTimeout)
+ {
+ _participatingClients = participatingClients;
+ _testInstance = testInstance;
+ _jmsDelegate = jmsDelegate;
+ _commandResponseTimeout = commandResponseTimeout;
+ _testResultsLatch = new CountDownLatch(testInstance.getTotalNumberOfParticipants());
+ _testResultTimeout = testResultTimeout;
+ _testResult = new TestResult(testInstance.getName());
+ }
+
+ public TestResult run()
+ {
+ final ParticipantResultListener participantResultListener = new ParticipantResultListener();
+ TestCommandResponseListener testCommandResponseListener = new TestCommandResponseListener();
+
+ try
+ {
+ _jmsDelegate.addCommandListener(testCommandResponseListener);
+ _jmsDelegate.addCommandListener(participantResultListener);
+
+ runParts();
+
+ return _testResult;
+ }
+ finally
+ {
+ _jmsDelegate.removeCommandListener(participantResultListener);
+ _jmsDelegate.removeCommandListener(testCommandResponseListener);
+ }
+ }
+
+ private void runParts()
+ {
+ boolean queuesCreated = false;
+ try
+ {
+ createQueues();
+ queuesCreated = true;
+ sendTestSetupCommands();
+ awaitCommandResponses();
+ sendCommandToParticipatingClients(new StartTestCommand());
+ awaitCommandResponses();
+
+ awaitTestResults();
+
+ sendCommandToParticipatingClients(new TearDownTestCommand());
+ awaitCommandResponses();
+ }
+ finally
+ {
+ if (queuesCreated)
+ {
+ deleteQueues();
+ }
+ }
+ }
+
+ void createQueues()
+ {
+ List<QueueConfig> queues = _testInstance.getQueues();
+ if (!queues.isEmpty())
+ {
+ _jmsDelegate.createQueues(queues);
+ }
+ }
+
+ void sendTestSetupCommands()
+ {
+ List<CommandForClient> commandsForAllClients = _testInstance.createCommands();
+ _commandResponseLatch = new CountDownLatch(commandsForAllClients.size());
+ for (CommandForClient commandForClient : commandsForAllClients)
+ {
+ String configuredClientName = commandForClient.getClientName();
+ String registeredClientName = _participatingClients.getRegisteredNameFromConfiguredName(configuredClientName);
+
+ Command command = commandForClient.getCommand();
+ sendCommandInternal(registeredClientName, command);
+ }
+ }
+
+ void awaitCommandResponses()
+ {
+ awaitLatch(_commandResponseLatch, _commandResponseTimeout, "Timed out waiting for command responses. Expecting %d more responses.");
+ }
+
+
+ void processCommandResponse(final Response response)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug("Received response for command " + response);
+ }
+
+ _commandResponseLatch.countDown();
+ checkForResponseError(response);
+ }
+
+
+ void awaitTestResults()
+ {
+ long timeout = _testResultTimeout;
+ DistributedTestException lastException = null;
+
+ boolean waitForever = _testResultTimeout == WAIT_FOREVER;
+ final long interval = waitForever ? PARTICIPANT_RESULTS_LOG_INTERVAL : Math.min(PARTICIPANT_RESULTS_LOG_INTERVAL, _testResultTimeout);
+
+ while(_testResultsLatch.getCount() > 0 && (waitForever || timeout > 0))
+ {
+ try
+ {
+ awaitLatch(_testResultsLatch, interval, "Waiting for participant results... Expecting %d more responses.");
+ }
+ catch (DistributedTestException e)
+ {
+ lastException = e;
+ LOGGER.info(e.getMessage());
+ }
+
+ if (!waitForever)
+ {
+ timeout =- interval;
+ }
+ }
+
+ if (_testResultsLatch.getCount() > 0)
+ {
+ throw lastException;
+ }
+ }
+
+ void deleteQueues()
+ {
+ List<QueueConfig> queues = _testInstance.getQueues();
+ if (!queues.isEmpty())
+ {
+ _jmsDelegate.deleteQueues(queues);
+ }
+ }
+
+ void sendCommandToParticipatingClients(final Command command)
+ {
+ Collection<String> participatingRegisteredClients = _participatingClients.getRegisteredNames();
+ _commandResponseLatch = new CountDownLatch(participatingRegisteredClients.size());
+ for (final String clientName : participatingRegisteredClients)
+ {
+ sendCommandInternal(clientName, command);
+ }
+ }
+
+ public void processParticipantResult(ParticipantResult result)
+ {
+ setOriginalTestDetailsOn(result);
+
+ _testResult.addParticipantResult(result);
+ LOGGER.info("Received result " + result);
+
+ _testResultsLatch.countDown();
+ checkForResponseError(result);
+ }
+
+ private void setOriginalTestDetailsOn(ParticipantResult result)
+ {
+ // Client knows neither the configured client name nor test name
+ String registeredClientName = result.getRegisteredClientName();
+ String configuredClient = _participatingClients.getConfiguredNameFromRegisteredName(registeredClientName);
+
+ result.setConfiguredClientName(configuredClient);
+ result.setTestName(_testInstance.getName());
+ result.setIterationNumber(_testInstance.getIterationNumber());
+ }
+
+ private void sendCommandInternal(String registeredClientName, Command command)
+ {
+ _setOfResponsesToExpect.add(command.getType());
+ _jmsDelegate.sendCommandToClient(registeredClientName, command);
+ }
+
+ private void awaitLatch(CountDownLatch latch, long timeout, String messageWithOneDecimalPlaceholder)
+ {
+ try
+ {
+ final boolean countedDownOK = latch.await(timeout, TimeUnit.MILLISECONDS);
+ if (!countedDownOK)
+ {
+ final long latchCount = latch.getCount();
+ String formattedMessage = String.format(messageWithOneDecimalPlaceholder, latchCount);
+ throw new DistributedTestException(formattedMessage);
+ }
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private void checkForResponseError(final Response response)
+ {
+ if (response.hasError())
+ {
+ LOGGER.error("Client " + response.getRegisteredClientName() + " reported error " + response);
+ }
+ }
+
+ final class ParticipantResultListener implements CommandListener
+ {
+ @Override
+ public boolean supports(Command command)
+ {
+ return command instanceof ParticipantResult;
+ }
+
+ @Override
+ public void processCommand(Command command)
+ {
+ processParticipantResult((ParticipantResult) command);
+
+ }
+ }
+
+ final class TestCommandResponseListener implements CommandListener
+ {
+ @Override
+ public void processCommand(Command command)
+ {
+ processCommandResponse((Response)command);
+ }
+
+ @Override
+ public boolean supports(Command command)
+ {
+ CommandType type = command.getType();
+ if (type == CommandType.RESPONSE)
+ {
+ Response response = (Response)command;
+ return _setOfResponsesToExpect.contains(response.getInReplyToCommandType());
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java
new file mode 100644
index 0000000000..bf0e5afb9c
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.disttest.controller;
+
+import org.apache.qpid.disttest.controller.config.TestInstance;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+
+public class TestRunnerFactory
+{
+ public TestRunner createTestRunner(ParticipatingClients participatingClients, TestInstance testInstance, ControllerJmsDelegate jmsDelegate, long commandResponseTimeout, long testResultTimeout)
+ {
+ return new TestRunner(participatingClients, testInstance, jmsDelegate, commandResponseTimeout, testResultTimeout);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java
new file mode 100644
index 0000000000..4353a85cd3
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java
@@ -0,0 +1,113 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.Command;
+
+public class ClientConfig
+{
+ /*
+ * TODO add this field when repeating groups of clients need to be used. Talk to Phil and Keith!
+ * private int _instances;
+ */
+
+ private List<ConnectionConfig> _connections;
+ private List<MessageProviderConfig> _messageProviders;
+ private String _name;
+
+ public ClientConfig()
+ {
+ _name = null;
+ _connections = Collections.emptyList();
+ _messageProviders = Collections.emptyList();
+ }
+
+ public ClientConfig(String name, ConnectionConfig... connections)
+ {
+ this(name, Arrays.asList(connections), null);
+ }
+
+ public ClientConfig(String name, List<ConnectionConfig> connections, List<MessageProviderConfig> messageProviders)
+ {
+ _name = name;
+ _connections = connections;
+ if (messageProviders == null)
+ {
+ _messageProviders = Collections.emptyList();
+ }
+ else
+ {
+ _messageProviders = messageProviders;
+ }
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public List<ConnectionConfig> getConnections()
+ {
+ return Collections.unmodifiableList(_connections);
+ }
+
+ public List<CommandForClient> createCommands()
+ {
+ List<CommandForClient> commandsForClient = new ArrayList<CommandForClient>();
+
+ for (MessageProviderConfig messageProvider : _messageProviders)
+ {
+ Command command = messageProvider.createCommand();
+ commandsForClient.add(new CommandForClient(_name, command));
+ }
+ for (ConnectionConfig connection : _connections)
+ {
+ List<Command> commands = connection.createCommands();
+ for (Command command : commands)
+ {
+ commandsForClient.add(new CommandForClient(_name, command));
+ }
+ }
+ return commandsForClient;
+ }
+
+ public int getTotalNumberOfParticipants()
+ {
+ int numOfParticipants = 0;
+ for (ConnectionConfig connection : _connections)
+ {
+ numOfParticipants = numOfParticipants + connection.getTotalNumberOfParticipants();
+ }
+ return numOfParticipants;
+ }
+
+ public List<MessageProviderConfig> getMessageProviders()
+ {
+ return Collections.unmodifiableList(_messageProviders);
+ }
+
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java
new file mode 100644
index 0000000000..fe56137276
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java
@@ -0,0 +1,81 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class Config
+{
+ private List<TestConfig> _tests;
+
+ public Config()
+ {
+ super();
+ _tests = Collections.emptyList();
+ }
+
+ public Config(TestConfig... tests)
+ {
+ _tests = Arrays.asList(tests);
+ }
+
+ public List<TestInstance> getTests()
+ {
+ List<TestInstance> testInstances = new ArrayList<TestInstance>();
+ for (TestConfig testConfig : _tests)
+ {
+ int iterationNumber = 0;
+
+ List<IterationValue> iterationValues = testConfig.getIterationValues();
+ if(iterationValues.isEmpty())
+ {
+ testInstances.add(new TestInstance(testConfig));
+ }
+ else
+ {
+ for (IterationValue iterationValue : iterationValues)
+ {
+ testInstances.add(new TestInstance(testConfig, iterationNumber, iterationValue));
+ iterationNumber++;
+ }
+ }
+ }
+
+ return Collections.unmodifiableList(testInstances);
+ }
+
+ List<TestConfig> getTestConfigs()
+ {
+ return Collections.unmodifiableList(_tests);
+ }
+
+ public int getTotalNumberOfClients()
+ {
+ int numberOfClients = 0;
+ for (TestConfig testConfig : _tests)
+ {
+ numberOfClients = Math.max(testConfig.getTotalNumberOfClients(), numberOfClients);
+ }
+ return numberOfClients;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java
new file mode 100644
index 0000000000..6288b42eac
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.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.disttest.controller.config;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.Reader;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.json.PropertyValueAdapter;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class ConfigReader
+{
+
+ public Config getConfigFromFile(String fileName) throws FileNotFoundException
+ {
+ FileReader reader = new FileReader(fileName);
+
+ Config config = readConfig(reader);
+ return config;
+ }
+
+ public Config readConfig(Reader reader)
+ {
+ Gson gson = new GsonBuilder()
+ .registerTypeAdapter(PropertyValue.class, new PropertyValueAdapter())
+ .create();
+ Config config = gson.fromJson(reader, Config.class);
+ return config;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java
new file mode 100644
index 0000000000..e2cc31e21e
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java
@@ -0,0 +1,91 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+
+public class ConnectionConfig
+{
+ private String _name;
+ private List<SessionConfig> _sessions;
+ private String _factory;
+
+ // For Gson
+ public ConnectionConfig()
+ {
+ super();
+ _sessions = Collections.emptyList();
+ }
+
+ public ConnectionConfig(String name, String factory, SessionConfig... sessions)
+ {
+ super();
+ _name = name;
+ _factory = factory;
+ _sessions = Arrays.asList(sessions);
+
+ }
+
+ public List<SessionConfig> getSessions()
+ {
+ return Collections.unmodifiableList(_sessions);
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public List<Command> createCommands()
+ {
+ List<Command> commands = new ArrayList<Command>();
+ commands.add(createCommand());
+ for (SessionConfig sessionConfig : _sessions)
+ {
+ commands.addAll(sessionConfig.createCommands(_name));
+ }
+ return commands;
+ }
+
+ private CreateConnectionCommand createCommand()
+ {
+ CreateConnectionCommand command = new CreateConnectionCommand();
+ command.setConnectionName(_name);
+ command.setConnectionFactoryName(_factory);
+ return command;
+ }
+
+ public int getTotalNumberOfParticipants()
+ {
+ int numOfParticipants = 0;
+
+ for (SessionConfig sessionConfig : _sessions)
+ {
+ numOfParticipants = numOfParticipants + sessionConfig.getTotalNumberOfParticipants();
+ }
+ return numOfParticipants;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java
new file mode 100644
index 0000000000..ed47e02667
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java
@@ -0,0 +1,65 @@
+package org.apache.qpid.disttest.controller.config;
+
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+
+public class ConsumerConfig extends ParticipantConfig
+{
+ private boolean _isTopic;
+ private boolean _isDurableSubscription;
+ private boolean _isBrowsingSubscription;
+ private String _selector;
+ private boolean _noLocal;
+ private boolean _synchronous;
+
+ // For Gson
+ public ConsumerConfig()
+ {
+ _isTopic = false;
+ _isDurableSubscription = false;
+ _isBrowsingSubscription = false;
+ _selector = null;
+ _noLocal = false;
+ _synchronous = true;
+ }
+
+ public ConsumerConfig(
+ String consumerName,
+ String destinationName,
+ long numberOfMessages,
+ int batchSize,
+ long maximumDuration,
+ boolean isTopic,
+ boolean isDurableSubscription,
+ boolean isBrowsingSubscription,
+ String selector,
+ boolean noLocal,
+ boolean synchronous)
+ {
+ super(consumerName, destinationName, numberOfMessages, batchSize, maximumDuration);
+
+ _isTopic = isTopic;
+ _isDurableSubscription = isDurableSubscription;
+ _isBrowsingSubscription = isBrowsingSubscription;
+ _selector = selector;
+ _noLocal = noLocal;
+ _synchronous = synchronous;
+ }
+
+ public CreateConsumerCommand createCommand(String sessionName)
+ {
+ CreateConsumerCommand createConsumerCommand = new CreateConsumerCommand();
+
+ setParticipantProperties(createConsumerCommand);
+
+ createConsumerCommand.setSessionName(sessionName);
+ createConsumerCommand.setTopic(_isTopic);
+ createConsumerCommand.setDurableSubscription(_isDurableSubscription);
+ createConsumerCommand.setBrowsingSubscription(_isBrowsingSubscription);
+ createConsumerCommand.setSelector(_selector);
+ createConsumerCommand.setNoLocal(_noLocal);
+ createConsumerCommand.setSynchronous(_synchronous);
+
+ return createConsumerCommand;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java
new file mode 100644
index 0000000000..ef953a5d07
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java
@@ -0,0 +1,86 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.beanutils.BeanUtilsBean;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.message.Command;
+
+public class IterationValue
+{
+ private final Map<String, String> _iterationPropertyValuesWithUnderscores;
+
+ public IterationValue(Map<String, String> iterationMap)
+ {
+ _iterationPropertyValuesWithUnderscores = iterationMap;
+ }
+
+ public IterationValue()
+ {
+ _iterationPropertyValuesWithUnderscores = Collections.emptyMap();
+ }
+
+ public Map<String, String> getIterationPropertyValuesWithUnderscores()
+ {
+ return _iterationPropertyValuesWithUnderscores;
+ }
+
+ public void applyToCommand(Command command)
+ {
+ try
+ {
+ Map<String, String> withoutUnderscoresToMatchCommandPropertyNames = getIterationPropertyValuesWithoutUnderscores();
+ BeanUtilsBean.getInstance().copyProperties(command, withoutUnderscoresToMatchCommandPropertyNames);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new RuntimeException("Couldn't copy properties from iteration " + this + " to " + command, e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new RuntimeException("Couldn't copy properties from iteration " + this + " to " + command, e);
+ }
+ }
+
+ private Map<String, String> getIterationPropertyValuesWithoutUnderscores()
+ {
+ Map<String, String> iterationPropertyValues = new HashMap<String, String>();
+ for (String propertyNameWithUnderscore : _iterationPropertyValuesWithUnderscores.keySet())
+ {
+ String propertyName = propertyNameWithUnderscore.replaceFirst("_", "");
+ String propertyValue = _iterationPropertyValuesWithUnderscores.get(propertyNameWithUnderscore);
+
+ iterationPropertyValues.put(propertyName, propertyValue);
+ }
+ return iterationPropertyValues;
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("iterationMap", _iterationPropertyValuesWithUnderscores).toString();
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java
new file mode 100644
index 0000000000..318ec7f045
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java
@@ -0,0 +1,60 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.Map;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+
+public class MessageProviderConfig
+{
+ private String _name;
+ private Map<String, PropertyValue> _messageProperties;
+
+ public MessageProviderConfig()
+ {
+ super();
+ }
+
+ public MessageProviderConfig(String name, Map<String, PropertyValue> messageProperties)
+ {
+ super();
+ _name = name;
+ _messageProperties = messageProperties;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public Map<String, PropertyValue> getMessageProperties()
+ {
+ return _messageProperties;
+ }
+
+ public CreateMessageProviderCommand createCommand()
+ {
+ CreateMessageProviderCommand command = new CreateMessageProviderCommand();
+ command.setProviderName(_name);
+ command.setMessageProperties(_messageProperties);
+ return command;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java
new file mode 100644
index 0000000000..31037a3038
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java
@@ -0,0 +1,64 @@
+/*
+ * 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.disttest.controller.config;
+
+import org.apache.qpid.disttest.message.CreateParticpantCommand;
+
+public abstract class ParticipantConfig
+{
+ private String _destinationName;
+ private long _numberOfMessages;
+ private String _name;
+ private int _batchSize;
+ private long _maximumDuration;
+
+ // For GSON
+ public ParticipantConfig()
+ {
+ _name = null;
+ _destinationName = null;
+ _numberOfMessages = 0;
+ _batchSize = 0;
+ _maximumDuration = 0;
+ }
+
+ public ParticipantConfig(
+ String name,
+ String destinationName,
+ long numberOfMessages,
+ int batchSize,
+ long maximumDuration)
+ {
+ _name = name;
+ _destinationName = destinationName;
+ _numberOfMessages = numberOfMessages;
+ _batchSize = batchSize;
+ _maximumDuration = maximumDuration;
+ }
+
+ protected void setParticipantProperties(CreateParticpantCommand createParticipantCommand)
+ {
+ createParticipantCommand.setParticipantName(_name);
+ createParticipantCommand.setDestinationName(_destinationName);
+ createParticipantCommand.setNumberOfMessages(_numberOfMessages);
+ createParticipantCommand.setBatchSize(_batchSize);
+ createParticipantCommand.setMaximumDuration(_maximumDuration);
+ }
+
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java
new file mode 100644
index 0000000000..7806528a8c
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java
@@ -0,0 +1,90 @@
+/*
+ * 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.disttest.controller.config;
+
+import javax.jms.Message;
+
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+
+public class ProducerConfig extends ParticipantConfig
+{
+ private int _deliveryMode;
+ private int _messageSize;
+ private int _priority;
+ private long _timeToLive;
+ private long _interval;
+ private long _startDelay;
+ private String _messageProviderName;
+
+ // For Gson
+ public ProducerConfig()
+ {
+ _deliveryMode = Message.DEFAULT_DELIVERY_MODE;
+ _messageSize = 0;
+ _priority = Message.DEFAULT_PRIORITY;
+ _timeToLive = Message.DEFAULT_TIME_TO_LIVE;
+ _interval = 0;
+ _startDelay = 0;
+ _messageProviderName = null;
+ }
+
+ public ProducerConfig(
+ String producerName,
+ String destinationName,
+ long numberOfMessages,
+ int batchSize,
+ long maximumDuration,
+ int deliveryMode,
+ int messageSize,
+ int priority,
+ long timeToLive,
+ long interval,
+ long startDelay,
+ String messageProviderName)
+ {
+ super(producerName, destinationName, numberOfMessages, batchSize, maximumDuration);
+
+ _deliveryMode = deliveryMode;
+ _messageSize = messageSize;
+ _priority = priority;
+ _timeToLive = timeToLive;
+ _interval = interval;
+ _startDelay = startDelay;
+ _messageProviderName = messageProviderName;
+ }
+
+ public CreateProducerCommand createCommand(String sessionName)
+ {
+ CreateProducerCommand command = new CreateProducerCommand();
+
+ setParticipantProperties(command);
+
+ command.setSessionName(sessionName);
+ command.setDeliveryMode(_deliveryMode);
+ command.setMessageSize(_messageSize);
+ command.setPriority(_priority);
+ command.setTimeToLive(_timeToLive);
+ command.setInterval(_interval);
+ command.setStartDelay(_startDelay);
+ command.setMessageProviderName(_messageProviderName);
+
+ return command;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java
new file mode 100644
index 0000000000..cffc2b7c50
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java
@@ -0,0 +1,69 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+public class QueueConfig
+{
+ private String _name;
+ private boolean _durable;
+ private Map<String, Object> _attributes;
+
+ public QueueConfig()
+ {
+ super();
+ _attributes = Collections.emptyMap();
+ }
+
+ public QueueConfig(String name, boolean durable, Map<String, Object> attributes)
+ {
+ super();
+ this._name = name;
+ this._durable = durable;
+ this._attributes = attributes;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ // TODO x-qpid-capacity and x-qpid-flow-resume-capacity need to be typed as numeric but we currrently
+ // pass these as a string.
+ public Map<String, Object> getAttributes()
+ {
+ return _attributes;
+ }
+
+ public boolean isDurable()
+ {
+ return _durable;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java
new file mode 100644
index 0000000000..12372e5391
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java
@@ -0,0 +1,114 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.jms.Session;
+
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+
+public class SessionConfig
+{
+ private static final List<ProducerConfig> EMPTY_PRODUCER_LIST = Collections.emptyList();
+ private static final List<ConsumerConfig> EMPTY_CONSUMER_LIST = Collections.emptyList();
+
+ private int _acknowledgeMode;
+ private String _sessionName;
+ private List<ProducerConfig> _producers;
+ private List<ConsumerConfig> _consumers;
+
+ // For Gson
+ public SessionConfig()
+ {
+ this(null, Session.SESSION_TRANSACTED, EMPTY_CONSUMER_LIST, EMPTY_PRODUCER_LIST);
+ }
+
+ public SessionConfig(String sessionName, int acknowledgeMode, ProducerConfig...producers)
+ {
+ this(sessionName, acknowledgeMode, EMPTY_CONSUMER_LIST, Arrays.asList(producers));
+ }
+
+ public SessionConfig(String sessionName, int acknowledgeMode, ConsumerConfig... consumers)
+ {
+ this(sessionName, acknowledgeMode, Arrays.asList(consumers), EMPTY_PRODUCER_LIST);
+ }
+
+ public SessionConfig(String sessionName, int acknowledgeMode, List<ConsumerConfig> consumers, List<ProducerConfig> producers)
+ {
+ _sessionName = sessionName;
+ _acknowledgeMode = acknowledgeMode;
+ _consumers = consumers;
+ _producers = producers;
+ }
+
+ public int getAcknowledgeMode()
+ {
+ return _acknowledgeMode;
+ }
+
+ public String getSessionName()
+ {
+ return _sessionName;
+ }
+
+ public List<ProducerConfig> getProducers()
+ {
+ return Collections.unmodifiableList(_producers);
+ }
+
+ public List<ConsumerConfig> getConsumers()
+ {
+ return Collections.unmodifiableList(_consumers);
+ }
+
+ public List<Command> createCommands(String connectionName)
+ {
+ List<Command> commands = new ArrayList<Command>();
+ commands.add(createCommand(connectionName));
+ for (ProducerConfig producer : _producers)
+ {
+ commands.add(producer.createCommand(_sessionName));
+ }
+ for (ConsumerConfig consumer : _consumers)
+ {
+ commands.add(consumer.createCommand(_sessionName));
+ }
+ return commands;
+ }
+
+ private CreateSessionCommand createCommand(String connectionName)
+ {
+ CreateSessionCommand command = new CreateSessionCommand();
+ command.setAcknowledgeMode(_acknowledgeMode);
+ command.setConnectionName(connectionName);
+ command.setSessionName(_sessionName);
+ return command;
+ }
+
+ public int getTotalNumberOfParticipants()
+ {
+ return _producers.size() + _consumers.size();
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java
new file mode 100644
index 0000000000..2bb5f1b289
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java
@@ -0,0 +1,117 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.disttest.controller.CommandForClient;
+
+public class TestConfig
+{
+ private final String _name;
+
+ private final List<ClientConfig> _clients;
+
+ private final List<QueueConfig> _queues;
+
+ private final List<Map<String, String>> _iterations;
+
+ public TestConfig()
+ {
+ _clients = Collections.emptyList();
+ _queues = Collections.emptyList();
+ _name = null;
+ _iterations = Collections.emptyList();
+ }
+
+ public TestConfig(String name, ClientConfig[] clients, QueueConfig[] queues)
+ {
+ _clients = Arrays.asList(clients);
+ _queues = Arrays.asList(queues);
+ _name = name;
+ _iterations = Collections.emptyList();
+ }
+
+ public List<String> getClientNames()
+ {
+ List<String> clientNames = new ArrayList<String>();
+ for (ClientConfig clientConfig : _clients)
+ {
+ clientNames.add(clientConfig.getName());
+ }
+ return clientNames;
+ }
+
+ public int getTotalNumberOfClients()
+ {
+ return _clients.size();
+ }
+
+ public int getTotalNumberOfParticipants()
+ {
+ int numOfParticipants = 0;
+ for (ClientConfig client : _clients)
+ {
+ numOfParticipants = numOfParticipants + client.getTotalNumberOfParticipants();
+ }
+ return numOfParticipants;
+ }
+
+ public List<CommandForClient> createCommands()
+ {
+ List<CommandForClient> commandsForClients = new ArrayList<CommandForClient>();
+ for (ClientConfig client : _clients)
+ {
+ commandsForClients.addAll(client.createCommands());
+ }
+
+ return Collections.unmodifiableList(commandsForClients);
+ }
+
+ public List<QueueConfig> getQueues()
+ {
+ return Collections.unmodifiableList(_queues);
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public List<IterationValue> getIterationValues()
+ {
+ List<IterationValue> iterationValues = new ArrayList<IterationValue>();
+ for (Map<String, String> iterationMap : _iterations)
+ {
+ iterationValues.add(new IterationValue(iterationMap));
+ }
+
+ return iterationValues;
+ }
+
+ public List<ClientConfig> getClients()
+ {
+ return Collections.unmodifiableList(_clients);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java
new file mode 100644
index 0000000000..9f555ef4da
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java
@@ -0,0 +1,102 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.Command;
+
+public class TestInstance
+{
+ private static final IterationValue EMPTY_ITERATION_VALUES = new IterationValue();
+
+ private TestConfig _testConfig;
+ private IterationValue _iterationValue;
+ private int _iterationNumber;
+
+ public TestInstance(TestConfig testConfig, int iterationNumber, IterationValue iterationValue)
+ {
+ _testConfig = testConfig;
+ _iterationNumber = iterationNumber;
+ _iterationValue = iterationValue;
+ }
+
+ public TestInstance(TestConfig testConfig)
+ {
+ this(testConfig, 0, EMPTY_ITERATION_VALUES);
+ }
+
+ public List<CommandForClient> createCommands()
+ {
+ List<CommandForClient> commands = _testConfig.createCommands();
+ List<CommandForClient> newCommands = new ArrayList<CommandForClient>(commands.size());
+
+ for (CommandForClient commandForClient : commands)
+ {
+ String clientName = commandForClient.getClientName();
+ Command command = commandForClient.getCommand();
+
+ _iterationValue.applyToCommand(command);
+
+ newCommands.add(new CommandForClient(clientName, command));
+ }
+
+ return newCommands;
+
+ }
+
+ public String getName()
+ {
+ return _testConfig.getName();
+ }
+
+ public int getIterationNumber()
+ {
+ return _iterationNumber;
+ }
+
+ public int getTotalNumberOfParticipants()
+ {
+ return _testConfig.getTotalNumberOfParticipants();
+ }
+
+ public List<QueueConfig> getQueues()
+ {
+ return _testConfig.getQueues();
+ }
+
+ public List<String> getClientNames()
+ {
+ return _testConfig.getClientNames();
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("testName", getName())
+ .append("iterationNumber", _iterationNumber)
+ .toString();
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java
new file mode 100644
index 0000000000..a3c2c57473
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java
@@ -0,0 +1,575 @@
+/*
+ * 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.disttest.jms;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.DistributedTestConstants;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.MessageProvider;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientJmsDelegate
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ClientJmsDelegate.class);
+
+ private final Context _context;
+ private final Destination _controllerQueue;
+ private final Connection _controllerConnection;
+ private final Session _controllerSession;
+ private final MessageProducer _controlQueueProducer;
+
+ private final String _clientName;
+ private Queue _instructionQueue;
+
+ private Map<String, Connection> _testConnections;
+ private Map<String, Session> _testSessions;
+ private Map<String, MessageProducer> _testProducers;
+ private Map<String, MessageConsumer> _testConsumers;
+ private Map<String, MessageProvider> _testMessageProviders;
+
+ private final MessageProvider _defaultMessageProvider;
+
+ public ClientJmsDelegate(final Context context)
+ {
+ try
+ {
+ _context = context;
+ final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory");
+ _controllerConnection = connectionFactory.createConnection();
+ _controllerConnection.start();
+ _controllerQueue = (Destination) context.lookup(DistributedTestConstants.CONTROLLER_QUEUE_JNDI_NAME);
+ _controllerSession = _controllerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _controlQueueProducer = _controllerSession.createProducer(_controllerQueue);
+ _clientName = UUID.randomUUID().toString();
+ _testConnections = new HashMap<String, Connection>();
+ _testSessions = new HashMap<String, Session>();
+ _testProducers = new HashMap<String, MessageProducer>();
+ _testConsumers = new HashMap<String, MessageConsumer>();
+ _testMessageProviders = new HashMap<String, MessageProvider>();
+ _defaultMessageProvider = new MessageProvider(null);
+ }
+ catch (final NamingException ne)
+ {
+ throw new DistributedTestException("Unable to create client jms delegate", ne);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create client jms delegate", jmse);
+ }
+ }
+
+ public void setInstructionListener(final Client client)
+ {
+ try
+ {
+ _instructionQueue = _controllerSession.createTemporaryQueue();
+ final MessageConsumer instructionConsumer = _controllerSession.createConsumer(_instructionQueue);
+ instructionConsumer.setMessageListener(new MessageListener()
+ {
+ @Override
+ public void onMessage(final Message message)
+ {
+ client.processInstruction(JmsMessageAdaptor.messageToCommand(message));
+ }
+ });
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to setup instruction listener", jmse);
+ }
+ }
+
+ public void sendRegistrationMessage()
+ {
+ Command command;
+ try
+ {
+ command = new RegisterClientCommand(_clientName, _instructionQueue.getQueueName());
+ }
+ catch (final JMSException e)
+ {
+ throw new DistributedTestException(e);
+ }
+ sendCommand(command);
+ }
+
+ public void sendResponseMessage(final Response responseMessage)
+ {
+ sendCommand(responseMessage);
+ }
+
+ private void sendCommand(final Command command)
+ {
+ try
+ {
+ final Message message = JmsMessageAdaptor.commandToMessage(_controllerSession, command);
+ _controlQueueProducer.send(message);
+ LOGGER.debug("Sent message for " + command.getType() + ". message id: " + message.getJMSMessageID());
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to send command: " + command, jmse);
+ }
+ }
+
+ public void createConnection(final CreateConnectionCommand command)
+ {
+ try
+ {
+ final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup(command
+ .getConnectionFactoryName());
+ final Connection newConnection = connectionFactory.createConnection();
+ addConnection(command.getConnectionName(), newConnection);
+ }
+ catch (final NamingException ne)
+ {
+ throw new DistributedTestException("Unable to lookup factoryName: " + command.getConnectionFactoryName(),
+ ne);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create connection: " + command.getConnectionName()
+ + " (using factory name: " + command.getConnectionFactoryName() + ")", jmse);
+ }
+ }
+
+ public void createSession(final CreateSessionCommand command)
+ {
+ try
+ {
+ final Connection connection = _testConnections.get(command.getConnectionName());
+ if (connection == null)
+ {
+ throw new DistributedTestException("No test connection found called: " + command.getConnectionName(),
+ command);
+ }
+ final boolean transacted = command.getAcknowledgeMode() == Session.SESSION_TRANSACTED;
+ final Session newSession = connection.createSession(transacted, command.getAcknowledgeMode());
+ addSession(command.getSessionName(), newSession);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create new session: " + command, jmse);
+ }
+ }
+
+ public void createProducer(final CreateProducerCommand command)
+ {
+ try
+ {
+ final Session session = _testSessions.get(command.getSessionName());
+ if (session == null)
+ {
+ throw new DistributedTestException("No test session found called: " + command.getSessionName(), command);
+ }
+ final Destination destination = session.createQueue(command.getDestinationName());
+ final MessageProducer jmsProducer = session.createProducer(destination);
+ if (command.getPriority() != -1)
+ {
+ jmsProducer.setPriority(command.getPriority());
+ }
+ if (command.getTimeToLive() > 0)
+ {
+ jmsProducer.setTimeToLive(command.getTimeToLive());
+ }
+
+ if (command.getDeliveryMode() == DeliveryMode.NON_PERSISTENT
+ || command.getDeliveryMode() == DeliveryMode.PERSISTENT)
+ {
+ jmsProducer.setDeliveryMode(command.getDeliveryMode());
+ }
+
+ addProducer(command.getParticipantName(), jmsProducer);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create new producer: " + command, jmse);
+ }
+
+ }
+
+ public void createConsumer(final CreateConsumerCommand command)
+ {
+ try
+ {
+ final Session session = _testSessions.get(command.getSessionName());
+ if (session == null)
+ {
+ throw new DistributedTestException("No test session found called: " + command.getSessionName(), command);
+ }
+ final Destination destination = command.isTopic() ? session.createTopic(command.getDestinationName())
+ : session.createQueue(command.getDestinationName());
+ final MessageConsumer jmsConsumer = session.createConsumer(destination, command.getSelector());
+
+ _testConsumers.put(command.getParticipantName(), jmsConsumer);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create new consumer: " + command, jmse);
+ }
+ }
+
+ /**
+ * destroy the client. Don't call from the Dispatcher thread.
+ */
+ public void destroy()
+ {
+ try
+ {
+ // Stopping the connection allows in-flight onMessage calls to
+ // finish.
+ _controllerConnection.stop();
+
+ if (_controllerSession != null)
+ {
+ _controllerSession.close();
+ }
+ if (_controllerConnection != null)
+ {
+ _controllerConnection.close();
+ }
+
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to destroy cleanly", jmse);
+ }
+ }
+
+ public Destination getControllerQueue()
+ {
+ return _controllerQueue;
+ }
+
+ public String getClientName()
+ {
+ return _clientName;
+ }
+
+ public int getNoOfTestConnections()
+ {
+ return _testConnections.size();
+ }
+
+ public int getNoOfTestSessions()
+ {
+ return _testSessions.size();
+ }
+
+ public int getNoOfTestProducers()
+ {
+ return _testProducers.size();
+ }
+
+ public int getNoOfTestConsumers()
+ {
+ return _testConsumers.size();
+ }
+
+ public void startConnections()
+ {
+ // start connections for consumers
+ // it would be better if we could track consumer connections and start
+ // only those
+ if (!_testConsumers.isEmpty())
+ {
+ for (final Map.Entry<String, Connection> entry : _testConnections.entrySet())
+ {
+ final Connection connection = entry.getValue();
+ try
+ {
+ connection.start();
+ }
+ catch (final JMSException e)
+ {
+ throw new DistributedTestException("Failed to start connection '" + entry.getKey() + "' :"
+ + e.getLocalizedMessage());
+ }
+ }
+ }
+ }
+
+ public void commitOrAcknowledgeMessage(final Message message, final String sessionName)
+ {
+ try
+ {
+ final Session session = _testSessions.get(sessionName);
+ if (session.getTransacted())
+ {
+ session.commit();
+ }
+ else if (message != null && session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
+ {
+ message.acknowledge();
+ }
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to commit or acknowledge message on session: " +
+ sessionName, jmse);
+ }
+ }
+
+ public Message sendNextMessage(final CreateProducerCommand command)
+ {
+ Message sentMessage = null;
+ MessageProvider messageProvider = _testMessageProviders.get(command.getMessageProviderName());
+ if (messageProvider == null)
+ {
+ messageProvider = _defaultMessageProvider;
+ }
+
+ final Session session = _testSessions.get(command.getSessionName());
+ final MessageProducer producer = _testProducers.get(command.getParticipantName());
+ try
+ {
+ sentMessage = messageProvider.nextMessage(session, command);
+ int deliveryMode = producer.getDeliveryMode();
+ int priority = producer.getPriority();
+ long ttl = producer.getTimeToLive();
+ if (messageProvider.isPropertySet(MessageProvider.PRIORITY))
+ {
+ priority = sentMessage.getJMSPriority();
+ }
+ if (messageProvider.isPropertySet(MessageProvider.DELIVERY_MODE))
+ {
+ deliveryMode = sentMessage.getJMSDeliveryMode();
+ }
+ if (messageProvider.isPropertySet(MessageProvider.TTL))
+ {
+ ttl = sentMessage.getLongProperty(MessageProvider.TTL);
+ }
+ producer.send(sentMessage, deliveryMode, priority, ttl);
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to create and send message with producer: " +
+ command.getParticipantName() + " on session: " + command.getSessionName(), jmse);
+ }
+ return sentMessage;
+ }
+
+ protected void addSession(final String sessionName, final Session newSession)
+ {
+ _testSessions.put(sessionName, newSession);
+ }
+
+ protected void addConnection(final String connectionName, final Connection newConnection)
+ {
+ _testConnections.put(connectionName, newConnection);
+ }
+
+ protected void addProducer(final String producerName, final MessageProducer jmsProducer)
+ {
+ _testProducers.put(producerName, jmsProducer);
+ }
+
+ public Message consumeMessage(String consumerName, long receiveInterval)
+ {
+ Message consumedMessage = null;
+ MessageConsumer consumer = _testConsumers.get(consumerName);
+ try
+ {
+ consumedMessage = consumer.receive(receiveInterval);
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Unable to consume message with consumer: " + consumerName, e);
+ }
+ return consumedMessage;
+ }
+
+ public void registerListener(String consumerName, MessageListener messageListener)
+ {
+ MessageConsumer consumer = _testConsumers.get(consumerName);
+ try
+ {
+ consumer.setMessageListener(messageListener);
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Unable to register message listener with consumer: " + consumerName, e);
+ }
+ }
+
+ public void rollbackOrRecover(String sessionName)
+ {
+ try
+ {
+ final Session session = _testSessions.get(sessionName);
+ if (session.getTransacted())
+ {
+ session.rollback();
+ }
+ else if (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
+ {
+ session.recover();
+ }
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to rollback or recover on session: " +
+ sessionName, jmse);
+ }
+ }
+
+ public void releaseMessage(String sessionName)
+ {
+ try
+ {
+ final Session session = _testSessions.get(sessionName);
+ if (session.getTransacted())
+ {
+ session.rollback();
+ }
+ else
+ {
+ session.recover();
+ }
+ }
+ catch (final JMSException jmse)
+ {
+ LOGGER.warn("Unable to rollback or recover on session: " + sessionName, jmse);
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("clientName", _clientName).toString();
+ }
+
+ public void closeTestConnections()
+ {
+ StringBuilder jmsErrorMessages = new StringBuilder();
+ int failedCloseCounter = 0;
+ for (final Map.Entry<String, Connection> entry : _testConnections.entrySet())
+ {
+ final Connection connection = entry.getValue();
+ try
+ {
+ connection.close();
+ }
+ catch (final JMSException e)
+ {
+ LOGGER.error("Failed to close connection '" + entry.getKey() + "' :" + e.getLocalizedMessage(), e);
+ failedCloseCounter++;
+ if (jmsErrorMessages.length() > 0)
+ {
+ jmsErrorMessages.append('\n');
+ }
+ jmsErrorMessages.append(e.getMessage());
+ }
+ }
+ _testConnections.clear();
+ _testSessions.clear();
+ _testProducers.clear();
+ _testConsumers.clear();
+ if (failedCloseCounter > 0)
+ {
+ throw new DistributedTestException("Close failed for " + failedCloseCounter + " connection(s) with the following errors: " + jmsErrorMessages.toString());
+ }
+ }
+
+ public void closeTestConsumer(String consumerName)
+ {
+ MessageConsumer consumer = _testConsumers.get(consumerName);
+ if (consumer != null)
+ {
+ try
+ {
+ consumer.close();
+ LOGGER.info("Closed test consumer " + consumerName);
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Failed to close consumer: " + consumerName, e);
+ }
+ }
+ }
+
+ public void closeTestProducer(String producerName)
+ {
+ MessageProducer producer = _testProducers.get(producerName);
+ if (producer != null)
+ {
+ try
+ {
+ producer.close();
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Failed to close producer: " + producerName, e);
+ }
+ }
+ }
+
+ public int calculatePayloadSizeFrom(Message message)
+ {
+ try
+ {
+ if (message != null && message instanceof TextMessage)
+ {
+ return ((TextMessage) message).getText().getBytes().length;
+ }
+ // TODO support other message types
+ return 0;
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Unable to determine the payload size for message " + message, e);
+ }
+ }
+
+ public void createMessageProvider(CreateMessageProviderCommand command)
+ {
+ _testMessageProviders.put(command.getProviderName(), new MessageProvider(command.getMessageProperties()));
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java
new file mode 100644
index 0000000000..3bf8e6ff4a
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java
@@ -0,0 +1,210 @@
+/*
+ * 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.disttest.jms;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.CommandListener;
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ControllerJmsDelegate
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ControllerJmsDelegate.class);
+
+ private final Map<String, Destination> _clientNameToQueueMap = new ConcurrentHashMap<String, Destination>();
+ private final Connection _connection;
+ private final Destination _controllerQueue;
+ private final Session _session;
+ private final QueueCreator _queueCreator;
+
+ private List<CommandListener> _commandListeners = new CopyOnWriteArrayList<CommandListener>();
+
+ public ControllerJmsDelegate(final Context context) throws NamingException, JMSException
+ {
+ final ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("connectionfactory");
+ _connection = connectionFactory.createConnection();
+ _connection.start();
+ _controllerQueue = (Destination) context.lookup("controllerqueue");
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _queueCreator = new QpidQueueCreator();
+ }
+
+ public void start()
+ {
+ try
+ {
+ final MessageConsumer consumer = _session.createConsumer(_controllerQueue);
+ consumer.setMessageListener(new MessageListener()
+ {
+ @Override
+ public void onMessage(final Message message)
+ {
+ try
+ {
+ String jmsMessageID = message.getJMSMessageID();
+ LOGGER.debug("Received message " + jmsMessageID);
+
+ final Command command = JmsMessageAdaptor.messageToCommand(message);
+ LOGGER.debug("Converted message " + jmsMessageID + " into command: " + command);
+
+ processCommandWithFirstSupportingListener(command);
+ LOGGER.debug("Finished processing command for message " + jmsMessageID);
+ }
+ catch (Throwable t)
+ {
+ LOGGER.error("Can't handle JMS message", t);
+ }
+ }
+ });
+ }
+ catch (final JMSException e)
+ {
+ throw new DistributedTestException(e);
+ }
+ }
+
+ /** ensures connections are closed, otherwise the JVM may be prevented from terminating */
+ public void closeConnections()
+ {
+ try
+ {
+ _session.close();
+ }
+ catch (JMSException e)
+ {
+ LOGGER.error("Unable to close session", e);
+ }
+
+ try
+ {
+ _connection.stop();
+ }
+ catch (JMSException e)
+ {
+ LOGGER.error("Unable to stop connection", e);
+ }
+
+ try
+ {
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Unable to close connection", e);
+ }
+ }
+
+ public void registerClient(final RegisterClientCommand command)
+ {
+ final String clientName = command.getClientName();
+ final Destination clientIntructionQueue = createDestinationFromString(command.getClientQueueName());
+ _clientNameToQueueMap.put(clientName, clientIntructionQueue);
+ }
+
+ public void sendCommandToClient(final String clientName, final Command command)
+ {
+ final Destination clientQueue = _clientNameToQueueMap.get(clientName);
+ if (clientQueue == null)
+ {
+ throw new DistributedTestException("Client name " + clientName + " not known. I know about: "
+ + _clientNameToQueueMap.keySet());
+ }
+
+ try
+ {
+ final MessageProducer producer = _session.createProducer(clientQueue);
+ final Message message = JmsMessageAdaptor.commandToMessage(_session, command);
+
+ producer.send(message);
+ }
+ catch (final JMSException e)
+ {
+ throw new DistributedTestException(e);
+ }
+ }
+
+ private void processCommandWithFirstSupportingListener(Command command)
+ {
+ for (CommandListener listener : _commandListeners)
+ {
+ if (listener.supports(command))
+ {
+ listener.processCommand(command);
+ return;
+ }
+ }
+
+ throw new IllegalStateException("There is no registered listener to process command " + command);
+ }
+
+ private Destination createDestinationFromString(final String clientQueueName)
+ {
+ Destination clientIntructionQueue;
+ try
+ {
+ clientIntructionQueue = _session.createQueue(clientQueueName);
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Unable to create Destination from " + clientQueueName);
+ }
+ return clientIntructionQueue;
+ }
+
+ public void createQueues(List<QueueConfig> queues)
+ {
+ _queueCreator.createQueues(_connection, queues);
+ }
+
+ public void deleteQueues(List<QueueConfig> queues)
+ {
+ _queueCreator.deleteQueues(_connection, queues);
+ }
+
+ public void addCommandListener(CommandListener commandListener)
+ {
+ _commandListeners.add(commandListener);
+ }
+
+ public void removeCommandListener(CommandListener commandListener)
+ {
+ _commandListeners.remove(commandListener);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java
new file mode 100644
index 0000000000..c9dba21a74
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.disttest.jms;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.apache.qpid.disttest.DistributedTestConstants;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.json.JsonHandler;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateResponderCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+
+public class JmsMessageAdaptor
+{
+ public static Message commandToMessage(final Session session, final Command command)
+ {
+ Message jmsMessage = null;
+ try
+ {
+ jmsMessage = session.createMessage();
+ jmsMessage.setStringProperty(DistributedTestConstants.MSG_COMMAND_PROPERTY, command.getType().name());
+ final JsonHandler jsonHandler = new JsonHandler();
+ jmsMessage.setStringProperty(DistributedTestConstants.MSG_JSON_PROPERTY, jsonHandler.marshall(command));
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to convert command " + command + " to JMS Message", jmse);
+ }
+
+ return jmsMessage;
+ }
+
+ public static Command messageToCommand(final Message jmsMessage)
+ {
+ Command command = null;
+ try
+ {
+ final CommandType commandType = CommandType.valueOf(jmsMessage
+ .getStringProperty(DistributedTestConstants.MSG_COMMAND_PROPERTY));
+ final JsonHandler jsonHandler = new JsonHandler();
+ command = jsonHandler.unmarshall(jmsMessage.getStringProperty(DistributedTestConstants.MSG_JSON_PROPERTY),
+ getCommandClassFromType(commandType));
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to convert JMS message " + jmsMessage + " to command object",
+ jmse);
+ }
+ return command;
+ }
+
+ static Class<? extends Command> getCommandClassFromType(final CommandType type)
+ {
+ switch (type)
+ {
+ case CREATE_CONNECTION:
+ return CreateConnectionCommand.class;
+ case CREATE_SESSION:
+ return CreateSessionCommand.class;
+ case CREATE_PRODUCER:
+ return CreateProducerCommand.class;
+ case CREATE_CONSUMER:
+ return CreateConsumerCommand.class;
+ case CREATE_RESPONDER:
+ return CreateResponderCommand.class;
+ case NO_OP:
+ return NoOpCommand.class;
+ case REGISTER_CLIENT:
+ return RegisterClientCommand.class;
+ case STOP_CLIENT:
+ return StopClientCommand.class;
+ case RESPONSE:
+ return Response.class;
+ case START_TEST:
+ return StartTestCommand.class;
+ case TEAR_DOWN_TEST:
+ return TearDownTestCommand.class;
+ case PARTICIPANT_RESULT:
+ return ParticipantResult.class;
+ case CONSUMER_PARTICIPANT_RESULT:
+ return ConsumerParticipantResult.class;
+ case PRODUCER_PARTICIPANT_RESULT:
+ return ProducerParticipantResult.class;
+ case CREATE_MESSAGE_PROVIDER:
+ return CreateMessageProviderCommand.class;
+ default:
+ throw new DistributedTestException("No class defined for type: " + type);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java
new file mode 100644
index 0000000000..6b21181b2a
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java
@@ -0,0 +1,110 @@
+/*
+ * 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.disttest.jms;
+
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+import org.apache.qpid.framing.FieldTable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidQueueCreator implements QueueCreator
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(QpidQueueCreator.class);
+
+ private static final FieldTable EMPTY_QUEUE_BIND_ARGUMENTS = new FieldTable();
+
+ @Override
+ public void createQueues(Connection connection, List<QueueConfig> configs)
+ {
+ AMQSession<?, ?> session = createSession(connection);
+ for (QueueConfig queueConfig : configs)
+ {
+ createQueue(session, queueConfig);
+ }
+ }
+
+ @Override
+ public void deleteQueues(Connection connection, List<QueueConfig> configs)
+ {
+ AMQSession<?, ?> session = createSession(connection);
+ for (QueueConfig queueConfig : configs)
+ {
+ deleteQueue(session, queueConfig);
+ }
+ }
+
+ private void createQueue(AMQSession<?, ?> session, QueueConfig queueConfig)
+ {
+ try
+ {
+ AMQDestination destination = (AMQDestination) session.createQueue(queueConfig.getName());
+ boolean autoDelete = false;
+ boolean exclusive = false;
+ session.createQueue(destination.getAMQQueueName(), autoDelete,
+ queueConfig.isDurable(), exclusive, queueConfig.getAttributes());
+ session.bindQueue(destination.getAMQQueueName(), destination.getRoutingKey(),
+ EMPTY_QUEUE_BIND_ARGUMENTS, destination.getExchangeName(),
+ destination, autoDelete);
+
+ LOGGER.info("Created queue " + queueConfig);
+ }
+ catch (Exception e)
+ {
+ throw new DistributedTestException("Failed to create queue:" + queueConfig, e);
+ }
+ }
+
+ private void deleteQueue(AMQSession<?, ?> session, QueueConfig queueConfig)
+ {
+ try
+ {
+ // The Qpid AMQSession API currently makes the #deleteQueue method protected and the
+ // raw protocol method public. This should be changed then we should switch the below to
+ // use #deleteQueue.
+ AMQDestination destination = (AMQDestination) session.createQueue(queueConfig.getName());
+ session.sendQueueDelete(destination.getAMQQueueName());
+ LOGGER.info("Deleted queue " + queueConfig.getName());
+ }
+ catch (Exception e)
+ {
+ throw new DistributedTestException("Failed to delete queue:" + queueConfig.getName(), e);
+ }
+ }
+
+ private AMQSession<?, ?> createSession(Connection connection)
+ {
+ try
+ {
+ return (AMQSession<?, ?>) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+ catch (JMSException e)
+ {
+ throw new DistributedTestException("Failed to create session!", e);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java
new file mode 100644
index 0000000000..dd9faef39f
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java
@@ -0,0 +1,31 @@
+/*
+ * 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.disttest.jms;
+
+import java.util.List;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+
+public interface QueueCreator
+{
+ public void createQueues(final Connection connection, final List<QueueConfig> configs);
+ public void deleteQueues(final Connection connection, final List<QueueConfig> configs);
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java
new file mode 100644
index 0000000000..8e50cd4f11
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java
@@ -0,0 +1,43 @@
+/*
+ * 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.disttest.json;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.message.Command;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class JsonHandler
+{
+ private final Gson _gson = new GsonBuilder()
+ .registerTypeAdapter(PropertyValue.class, new PropertyValueAdapter())
+ .create();
+
+ public <T extends Command> T unmarshall(final String jsonParams, final Class<T> clazz)
+ {
+ return _gson.fromJson(jsonParams, clazz);
+ }
+
+ public <T extends Command> String marshall(final T command)
+ {
+ return _gson.toJson(command);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java
new file mode 100644
index 0000000000..94f712e652
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java
@@ -0,0 +1,147 @@
+/*
+ * 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.disttest.json;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.disttest.client.property.GeneratedPropertyValue;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.PropertyValueFactory;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public class PropertyValueAdapter implements JsonDeserializer<PropertyValue>, JsonSerializer<PropertyValue>
+{
+ private static final String DEF_FIELD = "@def";
+ private PropertyValueFactory _factory = new PropertyValueFactory();
+
+ @Override
+ public PropertyValue deserialize(JsonElement json, Type type, JsonDeserializationContext context)
+ throws JsonParseException
+ {
+ if (json.isJsonNull())
+ {
+ return null;
+ }
+ else if (json.isJsonPrimitive())
+ {
+ Object result = null;
+ JsonPrimitive primitive = json.getAsJsonPrimitive();
+ if (primitive.isString())
+ {
+ result = primitive.getAsString();
+ }
+ else if (primitive.isNumber())
+ {
+ String asString = primitive.getAsString();
+ if (asString.indexOf('.') != -1 || asString.indexOf('e') != -1)
+ {
+ result = primitive.getAsDouble();
+ }
+ else
+ {
+ result = primitive.getAsLong();
+ }
+ }
+ else if (primitive.isBoolean())
+ {
+ result = primitive.getAsBoolean();
+ }
+ else
+ {
+ throw new JsonParseException("Unsupported primitive value " + primitive);
+ }
+ return new SimplePropertyValue(result);
+ }
+ else if (json.isJsonArray())
+ {
+ JsonArray array = json.getAsJsonArray();
+ List<Object> result = new ArrayList<Object>(array.size());
+ for (JsonElement element : array)
+ {
+ result.add(context.deserialize(element, Object.class));
+ }
+ return new SimplePropertyValue(result);
+ }
+ else if (json.isJsonObject())
+ {
+ JsonObject object = json.getAsJsonObject();
+ JsonElement defElement = object.getAsJsonPrimitive(DEF_FIELD);
+ Class<?> classInstance = null;
+ if (defElement != null)
+ {
+ try
+ {
+ classInstance = _factory.getPropertyValueClass(defElement.getAsString());
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+ }
+ if (classInstance == null)
+ {
+ Map<String, Object> result = new HashMap<String, Object>();
+ for (Map.Entry<String, JsonElement> entry : object.entrySet())
+ {
+ Object value = context.deserialize(entry.getValue(), Object.class);
+ result.put(entry.getKey(), value);
+ }
+ return new SimplePropertyValue(result);
+ }
+ else
+ {
+ return context.deserialize(json, classInstance);
+ }
+ }
+ else
+ {
+ throw new JsonParseException("Unsupported JSON type " + json);
+ }
+ }
+
+ @Override
+ public JsonElement serialize(PropertyValue src, Type typeOfSrc, JsonSerializationContext context)
+ {
+ if (src instanceof GeneratedPropertyValue)
+ {
+ JsonObject object = (JsonObject) context.serialize(src, Object.class);
+ object.addProperty(DEF_FIELD, ((GeneratedPropertyValue) src).getDefinition());
+ return object;
+ }
+ else
+ {
+ return context.serialize(src.getValue(), Object.class);
+ }
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java
new file mode 100644
index 0000000000..86b4d0e439
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java
@@ -0,0 +1,56 @@
+/*
+ * 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.disttest.message;
+
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.qpid.disttest.Visitor;
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.controller.Controller;
+
+/**
+ * A command sent between the {@link Controller} and a {@link Client}
+ */
+public abstract class Command
+{
+ private final CommandType type;
+
+ public Command(final CommandType type)
+ {
+ this.type = type;
+ }
+
+ public CommandType getType()
+ {
+ return type;
+ }
+
+ public void accept(Visitor visitor)
+ {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString()
+ {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java
new file mode 100644
index 0000000000..b04cbdaba1
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.disttest.message;
+
+public enum CommandType
+{
+ CREATE_CONNECTION,
+ CREATE_CONSUMER,
+ CREATE_PRODUCER,
+ CREATE_RESPONDER,
+ CREATE_SESSION,
+ NO_OP,
+ REGISTER_CLIENT,
+ RESPONSE,
+ START_TEST,
+ STOP_CLIENT,
+ TEAR_DOWN_TEST,
+ PARTICIPANT_RESULT,
+ CONSUMER_PARTICIPANT_RESULT,
+ PRODUCER_PARTICIPANT_RESULT,
+ CREATE_MESSAGE_PROVIDER
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java
new file mode 100644
index 0000000000..f92e3ea538
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java
@@ -0,0 +1,118 @@
+/*
+ * 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.disttest.message;
+
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_BROWSIING_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_DURABLE_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_NO_LOCAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SELECTOR;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SYNCHRONOUS_CONSUMER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_TOPIC;
+
+public class ConsumerParticipantResult extends ParticipantResult
+{
+ private boolean _topic;
+ private boolean _durableSubscription;
+ private boolean _browsingSubscription;
+ private boolean _selector;
+ private boolean _noLocal;
+ private boolean _synchronousConsumer;
+
+ public ConsumerParticipantResult()
+ {
+ super(CommandType.CONSUMER_PARTICIPANT_RESULT);
+ }
+
+ public ConsumerParticipantResult(String participantName)
+ {
+ this();
+ setParticipantName(participantName);
+ }
+
+ @OutputAttribute(attribute=IS_DURABLE_SUBSCRIPTION)
+ public boolean isDurableSubscription()
+ {
+ return _durableSubscription;
+ }
+
+ public void setDurableSubscription(boolean durable)
+ {
+ _durableSubscription = durable;
+ }
+
+
+ @OutputAttribute(attribute=IS_BROWSIING_SUBSCRIPTION)
+ public boolean isBrowsingSubscription()
+ {
+ return _browsingSubscription;
+ }
+
+ public void setBrowsingSubscription(boolean browsingSubscription)
+ {
+ _browsingSubscription = browsingSubscription;
+ }
+
+
+ @OutputAttribute(attribute=IS_SELECTOR)
+ public boolean isSelector()
+ {
+ return _selector;
+ }
+
+ public void setSelector(boolean selector)
+ {
+ _selector = selector;
+ }
+
+
+ @OutputAttribute(attribute=IS_NO_LOCAL)
+ public boolean isNoLocal()
+ {
+ return _noLocal;
+
+ }
+
+ public void setNoLocal(boolean noLocal)
+ {
+ _noLocal = noLocal;
+ }
+
+ @OutputAttribute(attribute=IS_SYNCHRONOUS_CONSUMER)
+ public boolean isSynchronousConsumer()
+ {
+ return _synchronousConsumer;
+ }
+
+ public void setSynchronousConsumer(boolean synchronousConsumer)
+ {
+ _synchronousConsumer = synchronousConsumer;
+ }
+
+
+ public void setTopic(boolean isTopic)
+ {
+ _topic = isTopic;
+ }
+
+ @OutputAttribute(attribute=IS_TOPIC)
+ public boolean isTopic()
+ {
+ return _topic;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java
new file mode 100644
index 0000000000..c5a96e9a94
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java
@@ -0,0 +1,58 @@
+/*
+ * 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.disttest.message;
+
+public class CreateConnectionCommand extends Command
+{
+ private String _connectionName;
+ private String _connectionFactoryName;
+
+ public CreateConnectionCommand()
+ {
+ super(CommandType.CREATE_CONNECTION);
+ }
+
+ public CreateConnectionCommand(String connectionName, String connectionFactoryName)
+ {
+ super(CommandType.CREATE_CONNECTION);
+ _connectionName = connectionName;
+ _connectionFactoryName = connectionFactoryName;
+ }
+
+ public void setConnectionName(final String connectionName)
+ {
+ this._connectionName = connectionName;
+ }
+
+ public String getConnectionName()
+ {
+ return _connectionName;
+ }
+
+ public void setConnectionFactoryName(final String connectionFactoryName)
+ {
+ this._connectionFactoryName = connectionFactoryName;
+ }
+
+ public String getConnectionFactoryName()
+ {
+ return _connectionFactoryName;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java
new file mode 100644
index 0000000000..678e428f94
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.disttest.message;
+
+public class CreateConsumerCommand extends CreateParticpantCommand
+{
+ private boolean _isTopic;
+ private boolean _isDurableSubscription;
+ private boolean _isBrowsingSubscription;
+ private String _selector;
+ private boolean _noLocal;
+ private boolean _synchronous;
+ private long _receiveTimeout = 5000;
+
+
+ public CreateConsumerCommand()
+ {
+ super(CommandType.CREATE_CONSUMER);
+ }
+
+ public boolean isDurableSubscription()
+ {
+ return _isDurableSubscription;
+ }
+
+ public void setDurableSubscription(final boolean isDurableSubscription)
+ {
+ this._isDurableSubscription = isDurableSubscription;
+ }
+
+ public boolean isBrowsingSubscription()
+ {
+ return _isBrowsingSubscription;
+ }
+
+ public void setBrowsingSubscription(final boolean isBrowsingSubscription)
+ {
+ _isBrowsingSubscription = isBrowsingSubscription;
+ }
+
+ public String getSelector()
+ {
+ return _selector;
+ }
+
+ public void setSelector(final String selector)
+ {
+ this._selector = selector;
+ }
+
+ public boolean isNoLocal()
+ {
+ return _noLocal;
+ }
+
+ public void setNoLocal(final boolean noLocal)
+ {
+ this._noLocal = noLocal;
+ }
+
+ public boolean isTopic()
+ {
+ return _isTopic;
+ }
+
+ public void setTopic(boolean isTopic)
+ {
+ this._isTopic = isTopic;
+ }
+
+ public boolean isSynchronous()
+ {
+ return _synchronous;
+ }
+
+ public void setSynchronous(boolean synchronous)
+ {
+ _synchronous = synchronous;
+ }
+
+ public void setReceiveTimeout(long receiveTimeout)
+ {
+ _receiveTimeout = receiveTimeout;
+
+ }
+
+ public long getReceiveTimeout()
+ {
+ return _receiveTimeout;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java
new file mode 100644
index 0000000000..3f30fdd96a
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java
@@ -0,0 +1,54 @@
+/*
+ * 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.disttest.message;
+
+import java.util.Map;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+
+public class CreateMessageProviderCommand extends Command
+{
+ private String _providerName;
+ private Map<String, PropertyValue> _messageProperties;
+
+ public CreateMessageProviderCommand()
+ {
+ super(CommandType.CREATE_MESSAGE_PROVIDER);
+ }
+
+ public String getProviderName()
+ {
+ return _providerName;
+ }
+
+ public void setProviderName(String providerName)
+ {
+ this._providerName = providerName;
+ }
+
+ public Map<String, PropertyValue> getMessageProperties()
+ {
+ return _messageProperties;
+ }
+
+ public void setMessageProperties(Map<String, PropertyValue> messageProperties)
+ {
+ this._messageProperties = messageProperties;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java
new file mode 100644
index 0000000000..f5d4a3ae9b
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java
@@ -0,0 +1,96 @@
+/*
+ * 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.disttest.message;
+
+public abstract class CreateParticpantCommand extends Command
+{
+ private String _participantName;
+ private String _sessionName;
+ private String _destinationName;
+ private long _numberOfMessages;
+ private int _batchSize;
+ private long _maximumDuration;
+
+ public CreateParticpantCommand(CommandType type)
+ {
+ super(type);
+ }
+
+ public String getParticipantName()
+ {
+ return _participantName;
+ }
+
+ public void setParticipantName(final String participantName)
+ {
+ _participantName = participantName;
+ }
+
+ public String getSessionName()
+ {
+ return _sessionName;
+ }
+
+ public void setSessionName(final String sessionName)
+ {
+ _sessionName = sessionName;
+ }
+
+ public String getDestinationName()
+ {
+ return _destinationName;
+ }
+
+ public void setDestinationName(final String destinationName)
+ {
+ _destinationName = destinationName;
+ }
+
+ public long getNumberOfMessages()
+ {
+ return _numberOfMessages;
+ }
+
+ public void setNumberOfMessages(final long numberOfMessages)
+ {
+ _numberOfMessages = numberOfMessages;
+ }
+
+ public int getBatchSize()
+ {
+ return _batchSize;
+ }
+
+ public void setBatchSize(int batchSize)
+ {
+ _batchSize = batchSize;
+ }
+
+ public long getMaximumDuration()
+ {
+ return _maximumDuration;
+ }
+
+ public void setMaximumDuration(long maximumDuration)
+ {
+ _maximumDuration = maximumDuration;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java
new file mode 100644
index 0000000000..69dfe1ff5a
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java
@@ -0,0 +1,106 @@
+/*
+ * 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.disttest.message;
+
+public class CreateProducerCommand extends CreateParticpantCommand
+{
+ private int _deliveryMode;
+ private int _messageSize;
+ private int _priority;
+ private long _timeToLive;
+ private long _interval;
+ private long _startDelay;
+ private String _messageProviderName;
+
+ public CreateProducerCommand()
+ {
+ super(CommandType.CREATE_PRODUCER);
+ }
+
+ public int getMessageSize()
+ {
+ return _messageSize;
+ }
+
+ public void setMessageSize(final int messageSize)
+ {
+ this._messageSize = messageSize;
+ }
+
+ public int getPriority()
+ {
+ return _priority;
+ }
+
+ public void setPriority(final int priority)
+ {
+ this._priority = priority;
+ }
+
+ public int getDeliveryMode()
+ {
+ return _deliveryMode;
+ }
+
+ public void setDeliveryMode(final int deliveryMode)
+ {
+ this._deliveryMode = deliveryMode;
+ }
+
+ public long getTimeToLive()
+ {
+ return _timeToLive;
+ }
+
+ public void setTimeToLive(final long timeToLive)
+ {
+ this._timeToLive = timeToLive;
+ }
+
+ public long getInterval()
+ {
+ return _interval;
+ }
+
+ public void setInterval(long interval)
+ {
+ this._interval = interval;
+ }
+
+ public long getStartDelay()
+ {
+ return _startDelay;
+ }
+
+ public void setStartDelay(long startDelay)
+ {
+ this._startDelay = startDelay;
+ }
+
+ public String getMessageProviderName()
+ {
+ return _messageProviderName;
+ }
+
+ public void setMessageProviderName(String messageProviderName)
+ {
+ this._messageProviderName = messageProviderName;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java
new file mode 100644
index 0000000000..85a2b5e548
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java
@@ -0,0 +1,28 @@
+/*
+ * 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.disttest.message;
+
+public class CreateResponderCommand extends Command
+{
+ public CreateResponderCommand()
+ {
+ super(CommandType.CREATE_RESPONDER);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java
new file mode 100644
index 0000000000..f6f59c26af
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java
@@ -0,0 +1,62 @@
+/*
+ * 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.disttest.message;
+
+public class CreateSessionCommand extends Command
+{
+ private String sessionName;
+ private String connectionName;
+ private int acknowledgeMode;
+
+ public CreateSessionCommand()
+ {
+ super(CommandType.CREATE_SESSION);
+ }
+
+ public String getSessionName()
+ {
+ return sessionName;
+ }
+
+ public void setSessionName(final String sessionName)
+ {
+ this.sessionName = sessionName;
+ }
+
+ public String getConnectionName()
+ {
+ return connectionName;
+ }
+
+ public void setConnectionName(final String connectionName)
+ {
+ this.connectionName = connectionName;
+ }
+
+ public int getAcknowledgeMode()
+ {
+ return acknowledgeMode;
+ }
+
+ public void setAcknowledgeMode(final int acknowledgeMode)
+ {
+ this.acknowledgeMode = acknowledgeMode;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java
new file mode 100644
index 0000000000..1cdaf00163
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.disttest.message;
+
+
+public class NoOpCommand extends Command
+{
+ public NoOpCommand()
+ {
+ super(CommandType.NO_OP);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java
new file mode 100644
index 0000000000..b912eaa1cb
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.message;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Marks an attribute of {@link ParticipantResult} that should be written to the test output file.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OutputAttribute
+{
+ ParticipantAttribute attribute();
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java
new file mode 100644
index 0000000000..c2fb38cc96
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java
@@ -0,0 +1,67 @@
+/*
+ * 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.disttest.message;
+
+import org.apache.qpid.disttest.client.Participant;
+
+/**
+ * Meta-date representing the attributes of {@link Participant} that we write to the test output file.
+ *
+ * Order of declaration is currently important - it determines they order they appear in the output.
+ *
+ * @see OutputAttribute
+ */
+public enum ParticipantAttribute
+{
+ TEST_NAME("Test Name"),
+ ITERATION_NUMBER("Iteration number"),
+ CONFIGURED_CLIENT_NAME("Client Name"),
+ PARTICIPANT_NAME("Participant name"),
+ NUMBER_OF_MESSAGES_PROCESSED("Number of messages"),
+ PAYLOAD_SIZE("Payload size (bytes)"),
+ PRIORITY("Priority"),
+ TIME_TO_LIVE("Time to live (ms)"),
+ DELIVERY_MODE("Delivery mode"),
+ BATCH_SIZE("Batch size"),
+ MAXIMUM_DURATION("Maximum duration (ms)"),
+ PRODUCER_START_DELAY("Producer start delay (ms)"),
+ PRODUCER_INTERVAL("Producer interval (ms)"),
+ IS_TOPIC("Is topic"),
+ IS_DURABLE_SUBSCRIPTION("Is durable subscription"),
+ IS_BROWSIING_SUBSCRIPTION("Is browsing subscription"),
+ IS_SELECTOR("Is selector"),
+ IS_NO_LOCAL("Is no local"),
+ IS_SYNCHRONOUS_CONSUMER("Is synchronous consumer"),
+ TOTAL_PAYLOAD_PROCESSED("Total payload processed (bytes)"),
+ THROUGHPUT("Throughput (kbytes/s)"),
+ TIME_TAKEN("Time taken (ms)"),
+ ERROR_MESSAGE("Error message");
+
+ private String _displayName;
+
+ ParticipantAttribute(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java
new file mode 100644
index 0000000000..95a19ceefc
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java
@@ -0,0 +1,89 @@
+/*
+ * 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.disttest.message;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+
+public class ParticipantAttributeExtractor
+{
+ public static Map<ParticipantAttribute, Object> getAttributes(Object targetObject)
+ {
+ Map<ParticipantAttribute, Object> attributes = new HashMap<ParticipantAttribute, Object>();
+
+
+ PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(targetObject);
+ for (PropertyDescriptor propertyDescriptor : descriptors)
+ {
+ final Method readMethod = getPropertyReadMethod(targetObject, propertyDescriptor);
+
+ for (Annotation annotation : readMethod.getDeclaredAnnotations())
+ {
+ if (annotation instanceof OutputAttribute)
+ {
+ OutputAttribute outputAttribute = (OutputAttribute) annotation;
+
+ Object value = getPropertyValue(targetObject, propertyDescriptor.getName());
+ attributes.put(outputAttribute.attribute(), value);
+ }
+ }
+ }
+
+ return attributes;
+ }
+
+ public static Method getPropertyReadMethod(Object targetObject, PropertyDescriptor propertyDescriptor)
+ {
+ final Method readMethod = propertyDescriptor.getReadMethod();
+
+ if (readMethod == null)
+ {
+ throw new RuntimeException("No read method for property " + propertyDescriptor.getName() + " on " + targetObject);
+ }
+ return readMethod;
+ }
+
+ public static Object getPropertyValue(Object targetObject, String propertyName)
+ {
+ try
+ {
+ return PropertyUtils.getProperty(targetObject, propertyName);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new RuntimeException("Couldn't get value of property " + propertyName + " from " + targetObject, e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new RuntimeException("Couldn't get value of property " + propertyName + " from " + targetObject, e);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new RuntimeException("Couldn't get value of property " + propertyName + " from " + targetObject, e);
+ }
+
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java
new file mode 100644
index 0000000000..4550f10c65
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java
@@ -0,0 +1,231 @@
+/*
+ * 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.disttest.message;
+
+import static org.apache.qpid.disttest.message.ParticipantAttribute.BATCH_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.CONFIGURED_CLIENT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.ITERATION_NUMBER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.MAXIMUM_DURATION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PAYLOAD_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.NUMBER_OF_MESSAGES_PROCESSED;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.THROUGHPUT;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PARTICIPANT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TEST_NAME;
+
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Map;
+
+public class ParticipantResult extends Response
+{
+ private String _testName;
+ private String _participantName;
+ private long _startInMillis;
+ private long _endInMillis;
+ private int _batchSize;
+ private long _maximumDuration;
+ private int _iterationNumber;
+
+ private String _configuredClientName;
+
+ private long _numberOfMessagesProcessed;
+ private long _totalPayloadProcessed;
+ private int _payloadSize;
+ private double _throughput;
+
+ public static final Comparator<? super ParticipantResult> PARTICIPANT_NAME_COMPARATOR = new Comparator<ParticipantResult>()
+ {
+ @Override
+ public int compare(ParticipantResult participantResult1, ParticipantResult participantResult2)
+ {
+ return participantResult1.getParticipantName().compareTo(participantResult2.getParticipantName());
+ }
+ };
+
+ public ParticipantResult()
+ {
+ this(CommandType.PARTICIPANT_RESULT);
+ }
+
+ public ParticipantResult(CommandType commandType)
+ {
+ super(commandType);
+ }
+
+ public ParticipantResult(String participantName)
+ {
+ this();
+ setParticipantName(participantName);
+ }
+
+ @OutputAttribute(attribute=TEST_NAME)
+ public String getTestName()
+ {
+ return _testName;
+ }
+
+ public void setTestName(String testName)
+ {
+ _testName = testName;
+ }
+
+ @OutputAttribute(attribute=ITERATION_NUMBER)
+ public int getIterationNumber()
+ {
+ return _iterationNumber;
+ }
+
+ public void setIterationNumber(int iterationNumber)
+ {
+ _iterationNumber = iterationNumber;
+ }
+
+ public void setStartDate(Date start)
+ {
+ _startInMillis = start.getTime();
+ }
+
+ public void setEndDate(Date end)
+ {
+ _endInMillis = end.getTime();
+ }
+
+ public Date getStartDate()
+ {
+ return new Date(_startInMillis);
+ }
+
+ public Date getEndDate()
+ {
+ return new Date(_endInMillis);
+ }
+
+
+ public long getStartInMillis()
+ {
+ return _startInMillis;
+ }
+
+ public long getEndInMillis()
+ {
+ return _endInMillis;
+ }
+
+
+ @OutputAttribute(attribute=PARTICIPANT_NAME)
+ public String getParticipantName()
+ {
+ return _participantName;
+ }
+
+
+ public void setParticipantName(String participantName)
+ {
+ _participantName = participantName;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.TIME_TAKEN)
+ public long getTimeTaken()
+ {
+ return _endInMillis - _startInMillis;
+ }
+
+ @OutputAttribute(attribute=CONFIGURED_CLIENT_NAME)
+ public String getConfiguredClientName()
+ {
+ return _configuredClientName;
+ }
+
+ public void setConfiguredClientName(String configuredClientName)
+ {
+ _configuredClientName = configuredClientName;
+ }
+
+ @OutputAttribute(attribute=NUMBER_OF_MESSAGES_PROCESSED)
+ public long getNumberOfMessagesProcessed()
+ {
+ return _numberOfMessagesProcessed;
+ }
+
+ public void setNumberOfMessagesProcessed(long numberOfMessagesProcessed)
+ {
+ _numberOfMessagesProcessed = numberOfMessagesProcessed;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.TOTAL_PAYLOAD_PROCESSED)
+ public long getTotalPayloadProcessed()
+ {
+ return _totalPayloadProcessed;
+ }
+
+ @OutputAttribute(attribute = PAYLOAD_SIZE)
+ public int getPayloadSize()
+ {
+ return _payloadSize;
+ }
+
+ public void setPayloadSize(int payloadSize)
+ {
+ _payloadSize = payloadSize;
+ }
+
+ public void setTotalPayloadProcessed(long totalPayloadProcessed)
+ {
+ _totalPayloadProcessed = totalPayloadProcessed;
+ }
+
+ public Map<ParticipantAttribute, Object> getAttributes()
+ {
+ return ParticipantAttributeExtractor.getAttributes(this);
+ }
+
+ public void setBatchSize(int batchSize)
+ {
+ _batchSize = batchSize;
+ }
+
+ @OutputAttribute(attribute=BATCH_SIZE)
+ public int getBatchSize()
+ {
+ return _batchSize;
+ }
+
+ public void setMaximumDuration(long maximumDuration)
+ {
+ _maximumDuration = maximumDuration;
+ }
+
+ @OutputAttribute(attribute=MAXIMUM_DURATION)
+ public long getMaximumDuration()
+ {
+ return _maximumDuration;
+ }
+
+ @OutputAttribute(attribute=THROUGHPUT)
+ public double getThroughput()
+ {
+ return _throughput;
+ }
+
+ public void setThroughput(double throughput)
+ {
+ _throughput = throughput;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java
new file mode 100644
index 0000000000..766c90eec8
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java
@@ -0,0 +1,100 @@
+/*
+ * 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.disttest.message;
+
+import static org.apache.qpid.disttest.message.ParticipantAttribute.DELIVERY_MODE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRIORITY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_INTERVAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_START_DELAY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TIME_TO_LIVE;
+
+public class ProducerParticipantResult extends ParticipantResult
+{
+ private int _priority;
+ private long _timeToLive;
+ private long _startDelay;
+ private long _interval;
+ private int _deliveryMode;
+ public ProducerParticipantResult()
+ {
+ super(CommandType.PRODUCER_PARTICIPANT_RESULT);
+ }
+
+ public ProducerParticipantResult(String participantName)
+ {
+ this();
+ setParticipantName(participantName);
+ }
+
+ @OutputAttribute(attribute=PRIORITY)
+ public int getPriority()
+ {
+ return _priority;
+ }
+
+ public void setPriority(int priority)
+ {
+ _priority = priority;
+ }
+
+ @OutputAttribute(attribute=TIME_TO_LIVE)
+ public long getTimeToLive()
+ {
+ return _timeToLive;
+ }
+
+ public void setTimeToLive(long timeToLive)
+ {
+ _timeToLive = timeToLive;
+ }
+
+ @OutputAttribute(attribute=PRODUCER_START_DELAY)
+ public long getStartDelay()
+ {
+ return _startDelay;
+ }
+
+ public void setStartDelay(long startDelay)
+ {
+ _startDelay = startDelay;
+ }
+
+ @OutputAttribute(attribute=PRODUCER_INTERVAL)
+ public long getInterval()
+ {
+ return _interval;
+ }
+
+ public void setInterval(long producerInterval)
+ {
+ _interval = producerInterval;
+ }
+
+ @OutputAttribute(attribute=DELIVERY_MODE)
+ public int getDeliveryMode()
+ {
+ return _deliveryMode;
+ }
+
+ public void setDeliveryMode(int deliveryMode)
+ {
+ this._deliveryMode = deliveryMode;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java
new file mode 100644
index 0000000000..af880a37d9
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java
@@ -0,0 +1,43 @@
+/*
+ * 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.disttest.message;
+
+public class RegisterClientCommand extends Command
+{
+ private final String _clientName;
+ private final String _clientQueueName;
+
+ public RegisterClientCommand(final String clientName, final String clientQueueName)
+ {
+ super(CommandType.REGISTER_CLIENT);
+ _clientName = clientName;
+ _clientQueueName = clientQueueName;
+ }
+
+ public String getClientName()
+ {
+ return _clientName;
+ }
+
+ public String getClientQueueName()
+ {
+ return _clientQueueName;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java
new file mode 100644
index 0000000000..aac056efcb
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java
@@ -0,0 +1,80 @@
+/*
+ * 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.disttest.message;
+
+
+public class Response extends Command
+{
+ protected String _registeredClientName;
+ protected String _errorMessage;
+ private CommandType _inReplyToCommandType;
+
+ public Response(final String registeredclientName, final CommandType inReplyToCommandType, final String errorMessage)
+ {
+ super(CommandType.RESPONSE);
+ _registeredClientName = registeredclientName;
+ _errorMessage = errorMessage;
+ _inReplyToCommandType = inReplyToCommandType;
+ }
+
+ public Response(String clientName, CommandType inReplyToCommandType)
+ {
+ this(clientName, inReplyToCommandType, null);
+ }
+
+ /**
+ * Provided so that subclasses can call super(commandType)
+ */
+ protected Response(CommandType commandType)
+ {
+ super(commandType);
+ }
+
+ public String getRegisteredClientName()
+ {
+ return _registeredClientName;
+ }
+
+ public void setRegisteredClientName(String registeredClientName)
+ {
+ _registeredClientName = registeredClientName;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.ERROR_MESSAGE)
+ public String getErrorMessage()
+ {
+ return _errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage)
+ {
+ _errorMessage = errorMessage;
+ }
+
+ public boolean hasError()
+ {
+ return _errorMessage != null;
+ }
+
+ public CommandType getInReplyToCommandType()
+ {
+ return _inReplyToCommandType;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java
new file mode 100644
index 0000000000..4a53697ecd
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java
@@ -0,0 +1,29 @@
+/*
+ * 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.disttest.message;
+
+public class StartTestCommand extends Command
+{
+
+ public StartTestCommand()
+ {
+ super(CommandType.START_TEST);
+ }
+
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java
new file mode 100644
index 0000000000..08758aaa69
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java
@@ -0,0 +1,28 @@
+/*
+ * 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.disttest.message;
+
+public class StopClientCommand extends Command
+{
+ public StopClientCommand()
+ {
+ super(CommandType.STOP_CLIENT);
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java
new file mode 100644
index 0000000000..6b1367d4f9
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java
@@ -0,0 +1,29 @@
+/*
+ * 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.disttest.message;
+
+public class TearDownTestCommand extends Command
+{
+
+ public TearDownTestCommand()
+ {
+ super(CommandType.TEAR_DOWN_TEST);
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java
new file mode 100644
index 0000000000..5e6da2e65b
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java
@@ -0,0 +1,97 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+
+public class AggregatedTestResult implements ITestResult
+{
+ private ParticipantResult _allParticipantResult;
+ private ParticipantResult _allConsumerParticipantResult;
+ private ParticipantResult _allProducerParticipantResult;
+ private final ITestResult _originalTestResult;
+
+ public AggregatedTestResult(ITestResult originalTestResult)
+ {
+ _originalTestResult = originalTestResult;
+ }
+
+ /**
+ * Returns the result where {@link ParticipantResult#getNumberOfMessagesProcessed()}
+ * is the total number of messages consumed during the test, and {@link ParticipantResult#getTimeTaken()}
+ * is the time between the start of the first producer and the end of the last consumer to finish.
+ */
+ public ParticipantResult getAllParticipantResult()
+ {
+ return _allParticipantResult;
+ }
+
+ public void setAllParticipantResult(ParticipantResult allParticipantResult)
+ {
+ _allParticipantResult = allParticipantResult;
+ }
+
+ public ParticipantResult getAllConsumerParticipantResult()
+ {
+ return _allConsumerParticipantResult;
+ }
+ public void setAllConsumerParticipantResult(ParticipantResult allConsumerParticipantResult)
+ {
+ _allConsumerParticipantResult = allConsumerParticipantResult;
+ }
+ public ParticipantResult getAllProducerParticipantResult()
+ {
+ return _allProducerParticipantResult;
+ }
+ public void setAllProducerParticipantResult(ParticipantResult allProducerParticipantResult)
+ {
+ _allProducerParticipantResult = allProducerParticipantResult;
+ }
+
+ // TODO should weaken to Collection
+ @Override
+ public List<ParticipantResult> getParticipantResults()
+ {
+ List<ParticipantResult> allParticipantResults = new ArrayList<ParticipantResult>(_originalTestResult.getParticipantResults());
+
+ allParticipantResults.add(_allConsumerParticipantResult);
+ allParticipantResults.add(_allProducerParticipantResult);
+ allParticipantResults.add(_allParticipantResult);
+
+ return allParticipantResults;
+ }
+
+ @Override
+ public boolean hasErrors()
+ {
+ return _originalTestResult.hasErrors();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _originalTestResult.getName();
+ }
+
+
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java
new file mode 100644
index 0000000000..cde30d36e5
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.results.aggregation;
+
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+
+public class Aggregator
+{
+
+ private TestResultAggregator _testResultAggregator = new TestResultAggregator();
+
+ public ResultsForAllTests aggregateResults(ResultsForAllTests rawResultsForAllTests)
+ {
+
+ ResultsForAllTests aggregatedResultsForAllTests = new ResultsForAllTests();
+
+
+ for (ITestResult testResult : rawResultsForAllTests.getTestResults())
+ {
+ AggregatedTestResult aggregateTestResult = _testResultAggregator.aggregateTestResult(testResult);
+ aggregatedResultsForAllTests.add(aggregateTestResult);
+ }
+
+
+ return aggregatedResultsForAllTests;
+ }
+
+ void setTestResultAggregator(TestResultAggregator testResultAggregator)
+ {
+ _testResultAggregator = testResultAggregator;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java
new file mode 100644
index 0000000000..3f9cdff69d
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.results.aggregation;
+
+import java.util.List;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+
+// TODO rename me!!
+public interface ITestResult
+{
+
+ // TODO should weaken to Collection
+ List<ParticipantResult> getParticipantResults();
+
+ boolean hasErrors();
+
+ String getName();
+
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java
new file mode 100644
index 0000000000..6c4e4f87ac
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java
@@ -0,0 +1,124 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import java.util.Date;
+import java.util.NavigableSet;
+import java.util.TreeSet;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+
+public class ParticipantResultAggregator
+{
+ private final String _aggregatedResultName;
+ private final Class<? extends ParticipantResult> _targetClass;
+
+ private long _minStartDate = Long.MAX_VALUE;
+ private long _maxEndDate = 0;
+ private long _numberOfMessagesProcessed = 0;
+ private long _totalPayloadProcessed = 0;
+
+ private NavigableSet<Integer> _encounteredPayloadSizes = new TreeSet<Integer>();
+ private NavigableSet<Integer> _encounteredIterationNumbers = new TreeSet<Integer>();
+ private NavigableSet<String> _encountedTestNames = new TreeSet<String>();
+
+ public ParticipantResultAggregator(Class<? extends ParticipantResult> taregtClass, String aggregateResultName)
+ {
+ _aggregatedResultName = aggregateResultName;
+ _targetClass = taregtClass;
+ }
+
+ public void aggregate(ParticipantResult result)
+ {
+ if (isAggregatable(result))
+ {
+ rollupConstantAttributes(result);
+ computeVariableAttributes(result);
+ }
+ }
+
+ public ParticipantResult getAggregatedResult()
+ {
+ ParticipantResult aggregatedResult = new ParticipantResult(_aggregatedResultName);
+
+ setRolledUpConstantAttributes(aggregatedResult);
+ setComputedVariableAttributes(aggregatedResult);
+
+ return aggregatedResult;
+ }
+
+ private boolean isAggregatable(ParticipantResult result)
+ {
+ return _targetClass.isAssignableFrom(result.getClass());
+ }
+
+ private void computeVariableAttributes(ParticipantResult result)
+ {
+ _numberOfMessagesProcessed += result.getNumberOfMessagesProcessed();
+ _totalPayloadProcessed += result.getTotalPayloadProcessed();
+ _minStartDate = Math.min(_minStartDate, result.getStartInMillis());
+ _maxEndDate = Math.max(_maxEndDate, result.getEndInMillis());
+ }
+
+ private void rollupConstantAttributes(ParticipantResult result)
+ {
+ if (result.getTestName() != null)
+ {
+ _encountedTestNames.add(result.getTestName());
+ }
+ _encounteredPayloadSizes.add(result.getPayloadSize());
+ _encounteredIterationNumbers.add(result.getIterationNumber());
+ }
+
+ private void setComputedVariableAttributes(ParticipantResult aggregatedResult)
+ {
+ aggregatedResult.setNumberOfMessagesProcessed(_numberOfMessagesProcessed);
+ aggregatedResult.setTotalPayloadProcessed(_totalPayloadProcessed);
+ aggregatedResult.setStartDate(new Date(_minStartDate));
+ aggregatedResult.setEndDate(new Date(_maxEndDate));
+ aggregatedResult.setThroughput(calculateThroughputInKiloBytesPerSecond());
+ }
+
+ private void setRolledUpConstantAttributes(ParticipantResult aggregatedResult)
+ {
+ if (_encounteredIterationNumbers.size() == 1)
+ {
+ aggregatedResult.setIterationNumber( _encounteredIterationNumbers.first());
+ }
+ if (_encounteredPayloadSizes.size() == 1)
+ {
+ aggregatedResult.setPayloadSize(_encounteredPayloadSizes.first());
+ }
+ if (_encountedTestNames.size() == 1)
+ {
+ aggregatedResult.setTestName(_encountedTestNames.first());
+ }
+ }
+
+ private double calculateThroughputInKiloBytesPerSecond()
+ {
+ double durationInMillis = _maxEndDate - _minStartDate;
+ double durationInSeconds = durationInMillis / 1000;
+ double totalPayloadProcessedInKiloBytes = ((double)_totalPayloadProcessed) / 1024;
+
+ return totalPayloadProcessedInKiloBytes/durationInSeconds;
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java
new file mode 100644
index 0000000000..1938add560
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java
@@ -0,0 +1,98 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+
+public class TestResultAggregator
+{
+ static final String AGGREGATED_ERROR_MESSAGE = "One or more participants reported errors.";
+ public static final String ALL_PARTICIPANTS_NAME = "All";
+ public static final String ALL_PRODUCER_PARTICIPANTS_NAME = "All Producers";
+ public static final String ALL_CONSUMER_PARTICIPANTS_NAME = "All Consumers";
+
+ public AggregatedTestResult aggregateTestResult(ITestResult originalTestResult)
+ {
+ AggregatedTestResult newTestResult = new AggregatedTestResult(originalTestResult);
+
+ ParticipantResultAggregator consumerParticipantResultAggregator = new ParticipantResultAggregator(ConsumerParticipantResult.class,
+ ALL_CONSUMER_PARTICIPANTS_NAME);
+ ParticipantResultAggregator producerParticipantResultAggregator = new ParticipantResultAggregator(ProducerParticipantResult.class,
+ ALL_PRODUCER_PARTICIPANTS_NAME);
+
+ boolean hasError = aggregate(originalTestResult,
+ consumerParticipantResultAggregator,
+ producerParticipantResultAggregator);
+
+ ParticipantResult aggregatedProducerResult = producerParticipantResultAggregator.getAggregatedResult();
+ newTestResult.setAllProducerParticipantResult(aggregatedProducerResult);
+
+ ParticipantResult aggregaredConsumerResult = consumerParticipantResultAggregator.getAggregatedResult();
+ newTestResult.setAllConsumerParticipantResult(aggregaredConsumerResult);
+
+ ParticipantResult aggregatedAllResult = buildAllResultFromOtherAggregatedResults(
+ aggregatedProducerResult, aggregaredConsumerResult);
+
+ if (hasError)
+ {
+ aggregatedAllResult.setErrorMessage(TestResultAggregator.AGGREGATED_ERROR_MESSAGE);
+ }
+ newTestResult.setAllParticipantResult(aggregatedAllResult);
+
+ return newTestResult;
+ }
+
+ private boolean aggregate(ITestResult originalTestResult,
+ ParticipantResultAggregator consumerParticipantResultAggregator,
+ ParticipantResultAggregator producerParticipantResultAggregator)
+ {
+ boolean hasError = false;
+ for (ParticipantResult result : originalTestResult.getParticipantResults())
+ {
+ consumerParticipantResultAggregator.aggregate(result);
+ producerParticipantResultAggregator.aggregate(result);
+
+ if (result.hasError())
+ {
+ hasError = true;
+ }
+ }
+ return hasError;
+ }
+
+ private ParticipantResult buildAllResultFromOtherAggregatedResults(
+ ParticipantResult aggregatedProducerResult, ParticipantResult aggregaredConsumerResult)
+ {
+ ParticipantResult aggregatedAllResult = new ParticipantResult(ALL_PARTICIPANTS_NAME);
+ aggregatedAllResult.setStartDate(aggregatedProducerResult.getStartDate());
+
+ aggregatedAllResult.setEndDate(aggregaredConsumerResult.getEndDate());
+
+ aggregatedAllResult.setIterationNumber(aggregaredConsumerResult.getIterationNumber());
+ aggregatedAllResult.setTestName(aggregaredConsumerResult.getTestName());
+ aggregatedAllResult.setNumberOfMessagesProcessed(aggregaredConsumerResult.getNumberOfMessagesProcessed());
+ aggregatedAllResult.setPayloadSize(aggregaredConsumerResult.getPayloadSize());
+ aggregatedAllResult.setTotalPayloadProcessed(aggregaredConsumerResult.getTotalPayloadProcessed());
+ aggregatedAllResult.setThroughput(aggregaredConsumerResult.getThroughput());
+
+ return aggregatedAllResult;
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java
new file mode 100644
index 0000000000..52e53ca624
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java
@@ -0,0 +1,89 @@
+/*
+ * 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.disttest.results.formatting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+import org.apache.qpid.disttest.message.ParticipantAttribute;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
+
+/**
+ * produces CSV output using the ordered enums in {@link ParticipantAttribute}
+ */
+public class CSVFormater
+{
+ public String format(ResultsForAllTests results)
+ {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(header());
+
+ List<ITestResult> testResults = results.getTestResults();
+
+ for (ITestResult testResult : testResults)
+ {
+
+ List<ParticipantResult> participantResults = new ArrayList<ParticipantResult>(testResult.getParticipantResults());
+ Collections.sort(participantResults, new CSVOrderParticipantResultComparator());
+
+ for (ParticipantResult participantResult : participantResults)
+ {
+ Map<ParticipantAttribute, Object> attributes = participantResult.getAttributes();
+ builder.append(row(attributes));
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * return a row, including a newline character at the end
+ */
+ private String row(Map<ParticipantAttribute, Object> attributeValueMap)
+ {
+ List<Object> attributeValues = new ArrayList<Object>();
+ for (ParticipantAttribute attribute : ParticipantAttribute.values())
+ {
+ attributeValues.add(attributeValueMap.get(attribute));
+ }
+
+ String row = StringUtils.join(attributeValues.toArray(), ",");
+ return row + "\n";
+ }
+
+ /** return the header row, including a newline at the end */
+ private String header()
+ {
+ List<String> displayNames = new ArrayList<String>();
+ for (ParticipantAttribute attribute : ParticipantAttribute.values())
+ {
+ displayNames.add(attribute.getDisplayName());
+ }
+
+ String header = StringUtils.join(displayNames.toArray(), ",");
+ return header + "\n";
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java
new file mode 100644
index 0000000000..0e1fbbc3c6
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java
@@ -0,0 +1,55 @@
+/*
+ * 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.disttest.results.formatting;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.builder.CompareToBuilder;
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+
+public class CSVOrderParticipantResultComparator implements Comparator<ParticipantResult>
+{
+ // TODO yuk
+ private static final Map<Class<? extends ParticipantResult>, Integer> TYPE_CODES = new HashMap<Class<? extends ParticipantResult>, Integer>();
+ static {
+ TYPE_CODES.put(ProducerParticipantResult.class, 0);
+ TYPE_CODES.put(ConsumerParticipantResult.class, 1);
+ TYPE_CODES.put(ParticipantResult.class, 2);
+ }
+
+ @Override
+ public int compare(ParticipantResult left, ParticipantResult right)
+ {
+ return new CompareToBuilder()
+ .append(getTypeCode(left), getTypeCode(right))
+ .append(left.getParticipantName(), right.getParticipantName())
+ .toComparison();
+ }
+
+
+ private int getTypeCode(ParticipantResult participantResult)
+ {
+ return TYPE_CODES.get(participantResult.getClass());
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/resources/perftests.properties b/qpid/java/perftests/src/main/resources/perftests.properties
new file mode 100644
index 0000000000..d8823f9dc5
--- /dev/null
+++ b/qpid/java/perftests/src/main/resources/perftests.properties
@@ -0,0 +1,20 @@
+# 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.
+
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+connectionfactory.connectionfactory = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java
new file mode 100644
index 0000000000..3be82627fe
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.disttest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class ArgumentParserTest extends QpidTestCase
+{
+ private static final String TEST_CONFIG_FILENAME = "ControllerRunnerTest-test-config-filename.json";
+ private static final String JNDI_CONFIG_FILENAME = "ControllerRunnerTest-jndi-config-filename.properties";
+ private static final String DISTRIBUTED_MODE = "true";
+
+ public static final String TEST_CONFIG_PROP = "test-config";
+ public static final String JNDI_CONFIG_PROP = "jndi-config";
+ public static final String DISTRIBUTED_PROP = "distributed";
+
+ public static final String TEST_CONFIG_DEFAULT = "perftests-config.json";
+ public static final String JNDI_CONFIG_DEFAULT = "perftests-jndi.properties";
+ public static final String DISTRIBUTED_DEFAULT = "false";
+
+ private Map<String,String> _options = new HashMap<String, String>();
+
+ private ArgumentParser _parser;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _parser = new ArgumentParser();
+
+ _options.clear();
+ _options.put(TEST_CONFIG_PROP, TEST_CONFIG_DEFAULT);
+ _options.put(JNDI_CONFIG_PROP, JNDI_CONFIG_DEFAULT);
+ _options.put(DISTRIBUTED_PROP, DISTRIBUTED_DEFAULT);
+ }
+
+ public void testInvalidArguments()
+ {
+ String[] args = new String[]{"nonExistentConfigProperty" + "=" + TEST_CONFIG_FILENAME};
+
+ try
+ {
+ _parser.parseArgumentsIntoConfig(_options, args);
+ fail("expected exception to be thrown due to provision of a non existent config property");
+ }
+ catch(IllegalArgumentException e)
+ {
+ //expected
+ }
+ }
+
+ public void testDefaultConfigValues()
+ {
+ String[] args = new String[0];
+
+ _parser.parseArgumentsIntoConfig(_options, args);
+
+ assertEquals("unexpected config value", TEST_CONFIG_DEFAULT, _options.get(TEST_CONFIG_PROP));
+ assertEquals("unexpected config value", JNDI_CONFIG_DEFAULT, _options.get(JNDI_CONFIG_PROP));
+ assertEquals("unexpected config value", DISTRIBUTED_DEFAULT, _options.get(DISTRIBUTED_PROP));
+ }
+
+ public void testConfigurationParsingOverridesDefault() throws Exception
+ {
+ String[] args = new String[]{TEST_CONFIG_PROP + "=" + TEST_CONFIG_FILENAME,
+ JNDI_CONFIG_PROP + "=" + JNDI_CONFIG_FILENAME,
+ DISTRIBUTED_PROP + "=" + DISTRIBUTED_MODE};
+
+ _parser.parseArgumentsIntoConfig(_options, args);
+
+ assertEquals("unexpected config value", TEST_CONFIG_FILENAME, _options.get(TEST_CONFIG_PROP));
+ assertEquals("unexpected config value", JNDI_CONFIG_FILENAME, _options.get(JNDI_CONFIG_PROP));
+ assertEquals("unexpected config value", DISTRIBUTED_MODE, _options.get(DISTRIBUTED_PROP));
+ assertFalse("override value was the same as the default", DISTRIBUTED_MODE.equalsIgnoreCase(_options.get(DISTRIBUTED_DEFAULT)));
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java
new file mode 100644
index 0000000000..12ba3b56ad
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.disttest;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.controller.config.ConfigReader;
+
+public class ConfigFileHelper
+{
+ public static Reader getConfigFileReader(Class<?> testClass, String resourceName)
+ {
+ InputStream inputStream = testClass.getResourceAsStream(resourceName);
+ if(inputStream == null)
+ {
+ throw new RuntimeException("Can't find resource " + resourceName + " using classloader of class " + testClass);
+ }
+ Reader reader = new InputStreamReader(inputStream);
+ return reader;
+ }
+
+ public static Config getConfigFromResource(Class<?> testClass, String resourceName)
+ {
+ ConfigReader configReader = new ConfigReader();
+ Config config = configReader.readConfig(getConfigFileReader(testClass, resourceName));
+ return config;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java
new file mode 100644
index 0000000000..320e7d8c9d
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.disttest;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.Command;
+
+
+public class VisitorTest extends TestCase
+{
+
+ public void testStringVisited() throws Exception
+ {
+ Object argument = new String();
+
+ TestVisitor visitor = new TestVisitor();
+ visitor.visit(argument);
+
+ assertSame(argument, visitor._string);
+ }
+
+ public void testCommandVisited() throws Exception
+ {
+ Object argument = new TestCommand();
+
+ TestVisitor visitor = new TestVisitor();
+ visitor.visit(argument);
+
+ assertSame(argument, visitor._testCommand);
+ }
+
+ public void testNoVisitIntegerImplementatiom() throws Exception
+ {
+ Integer argument = Integer.valueOf(1);
+
+ TestVisitor visitor = new TestVisitor();
+
+ try
+ {
+ visitor.visit(argument);
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ assertNotNull(e.getCause());
+ assertEquals(NoSuchMethodException.class, e.getCause().getClass());
+ }
+ }
+
+ class TestVisitor extends Visitor
+ {
+ String _string = null;
+ TestCommand _testCommand = null;
+
+ public void visit(String string)
+ {
+ _string = string;
+ }
+
+ public void visit(TestCommand command)
+ {
+ _testCommand = command;
+ }
+ }
+
+ class TestCommand extends Command
+ {
+
+ public TestCommand()
+ {
+ super(null);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java
new file mode 100644
index 0000000000..4a82f6719f
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.disttest.client;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+
+public class ClientCommandVisitorTest extends TestCase
+{
+ private Client _client;
+ private ClientCommandVisitor _visitor;
+ private ClientJmsDelegate _delegate;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _client = mock(Client.class);
+ _delegate = mock(ClientJmsDelegate.class);
+ _visitor = new ClientCommandVisitor(_client, _delegate);
+ }
+
+ public void testStopClient()
+ {
+ StopClientCommand command = new StopClientCommand();
+ _visitor.visit(command);
+ verify(_client).stop();
+ }
+
+ public void testCreateConnection() throws Exception
+ {
+ final CreateConnectionCommand command = new CreateConnectionCommand();
+ _visitor.visit(command);
+ verify(_delegate).createConnection(command);
+ }
+
+ public void testCreateSession() throws Exception
+ {
+ final CreateSessionCommand command = new CreateSessionCommand();
+ _visitor.visit(command);
+ verify(_delegate).createSession(command);
+ }
+
+ public void testCreateProducer() throws Exception
+ {
+ final CreateProducerCommand command = new CreateProducerCommand();
+ _visitor.visit(command);
+ verify(_delegate).createProducer(command);
+ }
+
+ public void testCreateConsumer() throws Exception
+ {
+ final CreateConsumerCommand command = new CreateConsumerCommand();
+ _visitor.visit(command);
+ verify(_delegate).createConsumer(command);
+ }
+
+ public void testStartTest() throws Exception
+ {
+ final StartTestCommand command = new StartTestCommand();
+ _visitor.visit(command);
+ verify(_client).startTest();
+ }
+
+ public void testStopTest() throws Exception
+ {
+ final TearDownTestCommand stopCommand = new TearDownTestCommand();
+ _visitor.visit(stopCommand);
+ verify(_client).tearDownTest();
+ }
+
+ public void testCreateMessageProvider() throws Exception
+ {
+ final CreateMessageProviderCommand command = new CreateMessageProviderCommand();
+ command.setProviderName("test");
+ _visitor.visit(command);
+ verify(_delegate).createMessageProvider(command);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java
new file mode 100644
index 0000000000..198baa6ef4
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.disttest.client;
+
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+public class ClientTest extends TestCase
+{
+ private Client _client;
+ private ClientJmsDelegate _delegate;
+ private ClientCommandVisitor _visitor;
+ private ParticipantExecutor _participant;
+ private ParticipantExecutorRegistry _participantRegistry;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _delegate = mock(ClientJmsDelegate.class);
+ _visitor = mock(ClientCommandVisitor.class);
+ _client = new Client(_delegate);
+ _client.setClientCommandVisitor(_visitor);
+ _participant = mock(ParticipantExecutor.class);
+ when(_participant.getParticipantName()).thenReturn("testParticipantMock");
+
+ _participantRegistry = mock(ParticipantExecutorRegistry.class);
+ when(_participantRegistry.executors()).thenReturn(Collections.singletonList(_participant));
+ _client.setParticipantRegistry(_participantRegistry);
+ }
+
+ public void testInitialState() throws Exception
+ {
+ assertEquals("Expected client to be in CREATED state", ClientState.CREATED, _client.getState());
+ }
+
+ public void testStart() throws Exception
+ {
+ _client.start();
+ final InOrder inOrder = inOrder(_delegate);
+ inOrder.verify(_delegate).setInstructionListener(_client);
+ inOrder.verify(_delegate).sendRegistrationMessage();
+ assertEquals("Expected client to be in STARTED state", ClientState.READY, _client.getState());
+ }
+
+ public void testStopClient() throws Exception
+ {
+ _client.stop();
+
+ assertEquals("Expected client to be in STOPPED state", ClientState.STOPPED, _client.getState());
+ }
+
+ public void testProcessInstructionVisitsCommandAndResponds() throws Exception
+ {
+ // has to be declared to be of supertype Command otherwise Mockito verify()
+ // refers to wrong method
+ final Command command = new StopClientCommand();
+ _client.processInstruction(command);
+
+ verify(_visitor).visit(command);
+ verify(_delegate).sendResponseMessage(isA(Response.class));
+ }
+
+ public void testWaitUntilStopped() throws Exception
+ {
+ stopClientLater(500);
+ _client.waitUntilStopped(1000);
+ verify(_delegate).destroy();
+ }
+
+ public void testStartTest() throws Exception
+ {
+ _client.start();
+ _client.addParticipantExecutor(_participant);
+
+ verify(_participantRegistry).add(_participant);
+
+ _client.startTest();
+
+ InOrder inOrder = Mockito.inOrder(_delegate, _participant);
+ inOrder.verify(_delegate).startConnections();
+ inOrder.verify(_participant).start(_client);
+ }
+
+ public void testTearDownTest() throws Exception
+ {
+ // before we can tear down the test the client needs to be in the "running test" state, which requires a participant
+ _client.start();
+ _client.addParticipantExecutor(_participant);
+ _client.startTest();
+
+ _client.tearDownTest();
+
+ verify(_delegate).closeTestConnections();
+
+ verify(_participantRegistry).clear();
+ }
+
+ public void testResults() throws Exception
+ {
+ ParticipantResult testResult = mock(ParticipantResult.class);
+ _client.sendResults(testResult);
+ verify(_delegate).sendResponseMessage(testResult);
+ }
+
+ private void stopClientLater(long delay)
+ {
+ doLater(new TimerTask()
+ {
+ @Override
+ public void run()
+ {
+ _client.stop();
+ }
+
+ }, delay);
+ }
+
+ private void doLater(TimerTask task, long delayInMillis)
+ {
+ Timer timer = new Timer();
+ timer.schedule(task, delayInMillis);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java
new file mode 100644
index 0000000000..805ebd3be4
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.disttest.client;
+
+import static org.apache.qpid.disttest.client.ParticipantTestHelper.assertExpectedResults;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.jms.Message;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.mockito.InOrder;
+
+public class ConsumerParticipantTest extends TestCase
+{
+ private static final String SESSION_NAME1 = "SESSION1";
+ private static final String PARTICIPANT_NAME1 = "PARTICIPANT_NAME1";
+ private static final long RECEIVE_TIMEOUT = 100;
+ private static final String CLIENT_NAME = "CLIENT_NAME";
+ private static final int PAYLOAD_SIZE_PER_MESSAGE = 1024;
+
+ private final Message _mockMessage = mock(Message.class);
+ private final CreateConsumerCommand _command = new CreateConsumerCommand();
+ private ClientJmsDelegate _delegate;
+ private ConsumerParticipant _consumerParticipant;
+ private InOrder _inOrder;
+
+ /** used to check start/end time of results */
+ private long _testStartTime;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _delegate = mock(ClientJmsDelegate.class);
+ _inOrder = inOrder(_delegate);
+
+ _command.setSessionName(SESSION_NAME1);
+ _command.setParticipantName(PARTICIPANT_NAME1);
+ _command.setSynchronous(true);
+ _command.setReceiveTimeout(RECEIVE_TIMEOUT);
+
+ _consumerParticipant = new ConsumerParticipant(_delegate, _command);
+
+ when(_delegate.consumeMessage(PARTICIPANT_NAME1, RECEIVE_TIMEOUT)).thenReturn(_mockMessage);
+ when(_delegate.calculatePayloadSizeFrom(_mockMessage)).thenReturn(PAYLOAD_SIZE_PER_MESSAGE);
+
+ _testStartTime = System.currentTimeMillis();
+ }
+
+ public void testNoMessagesToReceive() throws Exception
+ {
+ _command.setNumberOfMessages(0);
+ _command.setMaximumDuration(0);
+
+ try
+ {
+ _consumerParticipant.doIt(CLIENT_NAME);
+ fail("Exception not thrown");
+ }
+ catch(DistributedTestException e)
+ {
+ // PASS
+ assertEquals("number of messages and duration cannot both be zero", e.getMessage());
+
+ }
+
+ verify(_delegate, never()).consumeMessage(anyString(), anyLong());
+ }
+
+ public void testReceiveOneMessageSynch() throws Exception
+ {
+ int numberOfMessages = 1;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+ _command.setNumberOfMessages(numberOfMessages);
+
+ ParticipantResult result = _consumerParticipant.doIt(CLIENT_NAME);
+
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, PAYLOAD_SIZE_PER_MESSAGE, totalPayloadSize, null);
+
+ _inOrder.verify(_delegate).consumeMessage(PARTICIPANT_NAME1, RECEIVE_TIMEOUT);
+ _inOrder.verify(_delegate).calculatePayloadSizeFrom(_mockMessage);
+ _inOrder.verify(_delegate).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testReceiveMessagesForDurationSynch() throws Exception
+ {
+ long duration = 100;
+ _command.setMaximumDuration(duration);
+
+ ParticipantResult result = _consumerParticipant.doIt(CLIENT_NAME);
+
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, null, PAYLOAD_SIZE_PER_MESSAGE, null, duration);
+
+ verify(_delegate, atLeastOnce()).consumeMessage(PARTICIPANT_NAME1, RECEIVE_TIMEOUT);
+ verify(_delegate, atLeastOnce()).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, atLeastOnce()).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testReceiveMessagesBatchedSynch() throws Exception
+ {
+ int numberOfMessages = 10;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+ _command.setNumberOfMessages(numberOfMessages);
+ _command.setBatchSize(3);
+
+ ParticipantResult result = _consumerParticipant.doIt(CLIENT_NAME);
+
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, PAYLOAD_SIZE_PER_MESSAGE, totalPayloadSize, null);
+
+ verify(_delegate, times(numberOfMessages)).consumeMessage(PARTICIPANT_NAME1, RECEIVE_TIMEOUT);
+ verify(_delegate, times(numberOfMessages)).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, times(4)).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testReceiveMessagesWithVaryingPayloadSize() throws Exception
+ {
+ int numberOfMessages = 3;
+
+ int firstPayloadSize = PAYLOAD_SIZE_PER_MESSAGE;
+ int secondPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * 2;
+ int thirdPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * 4;
+
+ _command.setNumberOfMessages(numberOfMessages);
+
+ when(_delegate.calculatePayloadSizeFrom(_mockMessage)).thenReturn(firstPayloadSize, secondPayloadSize, thirdPayloadSize);
+
+ ParticipantResult result = _consumerParticipant.doIt(CLIENT_NAME);
+
+ final int expectedPayloadResultPayloadSize = 0;
+ final long totalPayloadSize = firstPayloadSize + secondPayloadSize + thirdPayloadSize;
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, expectedPayloadResultPayloadSize, totalPayloadSize, null);
+
+ verify(_delegate, times(numberOfMessages)).consumeMessage(PARTICIPANT_NAME1, RECEIVE_TIMEOUT);
+ verify(_delegate, times(numberOfMessages)).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, times(numberOfMessages)).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testReleaseResources()
+ {
+ _consumerParticipant.releaseResources();
+ verify(_delegate).closeTestConsumer(PARTICIPANT_NAME1);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java
new file mode 100644
index 0000000000..ffc3733eb7
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.disttest.client;
+
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.client.property.ListPropertyValue;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+
+public class MessageProviderTest extends TestCase
+{
+ private Session _session;
+ private TextMessage _message;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _session = mock(Session.class);
+ _message = mock(TextMessage.class);
+ when(_session.createTextMessage(isA(String.class))).thenReturn(_message);
+ when(_session.createTextMessage()).thenReturn(_message);
+ }
+
+ public void testGetMessagePayload() throws Exception
+ {
+ MessageProvider messageProvider = new MessageProvider(null)
+ {
+ public String getMessagePayload(CreateProducerCommand command)
+ {
+ return super.getMessagePayload(command);
+ }
+ };
+ CreateProducerCommand command = new CreateProducerCommand();
+ command.setMessageSize(100);
+ String payloadValue = messageProvider.getMessagePayload(command);
+ assertNotNull("Mesage payload should not be null", payloadValue);
+ assertEquals("Unexpected payload size", 100, payloadValue.length());
+ }
+
+ public void testNextMessage() throws Exception
+ {
+ MessageProvider messageProvider = new MessageProvider(null);
+ CreateProducerCommand command = new CreateProducerCommand();
+ command.setMessageSize(100);
+ Message message = messageProvider.nextMessage(_session, command);
+ assertNotNull("Mesage should be returned", message);
+ verify(_message, atLeastOnce()).setText(isA(String.class));
+ }
+
+ public void testNextMessageWithProperties() throws Exception
+ {
+ Map<String, PropertyValue> properties = new HashMap<String, PropertyValue>();
+ properties.put("test1", new SimplePropertyValue("testValue1"));
+ properties.put("test2", new SimplePropertyValue(new Integer(1)));
+ properties.put("priority", new SimplePropertyValue(new Integer(2)));
+ List<PropertyValue> listItems = new ArrayList<PropertyValue>();
+ listItems.add(new SimplePropertyValue(new Double(2.0)));
+ ListPropertyValue list = new ListPropertyValue();
+ list.setItems(listItems);
+ properties.put("test3", list);
+
+ MessageProvider messageProvider = new MessageProvider(properties);
+ CreateProducerCommand command = new CreateProducerCommand();
+ command.setMessageSize(100);
+ Message message = messageProvider.nextMessage(_session, command);
+ assertNotNull("Mesage should be returned", message);
+ verify(_message, atLeastOnce()).setText(isA(String.class));
+ verify(_message, atLeastOnce()).setJMSPriority(2);
+ verify(_message, atLeastOnce()).setStringProperty("test1", "testValue1");
+ verify(_message, atLeastOnce()).setIntProperty("test2", 1);
+ verify(_message, atLeastOnce()).setDoubleProperty("test3", 2.0);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java
new file mode 100644
index 0000000000..f30e4664ff
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.disttest.client;
+
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InOrder;
+
+public class ParticipantExecutorTest extends TestCase
+{
+ private static final ResultHasError HAS_ERROR = new ResultHasError();
+ private static final String CLIENT_NAME = "CLIENT_NAME";
+ private static final String PARTICIPANT_NAME = "PARTICIPANT_NAME";
+ private ParticipantExecutor _participantExecutor = null;
+ private Client _client = null;
+ private Participant _participant = null;
+ private ParticipantResult _mockResult;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _client = mock(Client.class);
+ when(_client.getClientName()).thenReturn(CLIENT_NAME);
+ _participant = mock(Participant.class);
+
+ _participantExecutor = new ParticipantExecutor(_participant);
+ _participantExecutor.setExecutor(new SynchronousExecutor());
+
+ _mockResult = mock(ParticipantResult.class);
+ }
+
+ public void testStart() throws Exception
+ {
+ when(_participant.doIt(CLIENT_NAME)).thenReturn(_mockResult);
+
+ _participantExecutor.start(_client);
+
+ InOrder inOrder = inOrder(_participant, _client);
+
+ inOrder.verify(_participant).doIt(CLIENT_NAME);
+ inOrder.verify(_client).sendResults(_mockResult);
+ inOrder.verify(_participant).releaseResources();
+ }
+
+ public void testParticipantThrowsException() throws Exception
+ {
+ when(_participant.doIt(CLIENT_NAME)).thenThrow(DistributedTestException.class);
+
+ _participantExecutor.start(_client);
+
+ InOrder inOrder = inOrder(_participant, _client);
+
+ inOrder.verify(_participant).doIt(CLIENT_NAME);
+ inOrder.verify(_client).sendResults(argThat(HAS_ERROR));
+ inOrder.verify(_participant).releaseResources();
+ }
+
+ public void testThreadNameAndDaemonness() throws Exception
+ {
+
+ ThreadPropertyReportingParticipant participant = new ThreadPropertyReportingParticipant(PARTICIPANT_NAME);
+ _participantExecutor = new ParticipantExecutor(participant);
+
+ _participantExecutor.start(_client);
+ participant.awaitExecution();
+
+ assertTrue("Participant should be run in a thread named after it", participant.threadWasCalled().endsWith(PARTICIPANT_NAME));
+ assertTrue("Executor should use daemon threads to avoid them preventing JVM termination", participant.wasDaemon());
+ }
+
+ private static final class ThreadPropertyReportingParticipant implements Participant
+ {
+ private final String _participantName;
+ private final CountDownLatch _participantExecuted = new CountDownLatch(1);
+ private String _threadName;
+ private boolean _daemon;
+
+ public ThreadPropertyReportingParticipant(String participantName)
+ {
+ _participantName = participantName;
+ }
+
+ public String threadWasCalled()
+ {
+ return _threadName;
+ }
+
+ public boolean wasDaemon()
+ {
+ return _daemon;
+ }
+
+ @Override
+ public void releaseResources()
+ {
+ }
+
+ @Override
+ public String getName()
+ {
+ return _participantName;
+ }
+
+ @Override
+ public ParticipantResult doIt(String registeredClientName) throws Exception
+ {
+ Thread currentThread = Thread.currentThread();
+ _threadName = currentThread.getName();
+ _daemon = currentThread.isDaemon();
+
+ _participantExecuted.countDown();
+
+ return null; // unused
+ }
+
+ public void awaitExecution()
+ {
+ boolean success = false;
+ try
+ {
+ success = _participantExecuted.await(5, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+
+ assertTrue("Participant not executed", success);
+ }
+ }
+
+ /** avoids our unit test needing to use multiple threads */
+ private final class SynchronousExecutor implements Executor
+ {
+ @Override
+ public void execute(Runnable command)
+ {
+ command.run();
+ }
+ }
+
+ private static class ResultHasError extends ArgumentMatcher<ParticipantResult>
+ {
+ @Override
+ public boolean matches(Object argument)
+ {
+ ParticipantResult result = (ParticipantResult) argument;
+ return result.hasError();
+ }
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java
new file mode 100644
index 0000000000..bd0d5a39c8
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.disttest.client;
+
+import static org.mockito.Mockito.mock;
+import junit.framework.TestCase;
+
+public class ParticipantRegistryTest extends TestCase
+{
+ private ParticipantExecutorRegistry _participantRegistry = new ParticipantExecutorRegistry();
+
+ private ParticipantExecutor _testParticipant1 = mock(ParticipantExecutor.class);
+ private ParticipantExecutor _testParticipant2 = mock(ParticipantExecutor.class);
+
+ public void testAdd()
+ {
+ assertTrue(_participantRegistry.executors().isEmpty());
+
+ _participantRegistry.add(_testParticipant1);
+
+ assertTrue(_participantRegistry.executors().contains(_testParticipant1));
+
+ _participantRegistry.add(_testParticipant2);
+
+ assertTrue(_participantRegistry.executors().contains(_testParticipant2));
+ }
+
+ public void testClear()
+ {
+ _participantRegistry.add(_testParticipant1);
+
+ assertEquals(1, _participantRegistry.executors().size());
+
+ _participantRegistry.clear();
+
+ assertTrue(_participantRegistry.executors().isEmpty());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java
new file mode 100644
index 0000000000..73836f68e5
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.client;
+
+import java.util.Date;
+
+import javax.jms.DeliveryMode;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateParticpantCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+
+public class ParticipantResultFactoryTest extends TestCase
+{
+ private static final String PARTICIPANT_NAME = "participantName";
+ private static final String REGISTERED_CLIENT_NAME = "registeredClientName";
+
+ private static final int BATCH_SIZE = 10;
+ private static final long MAXIMUM_DURATION = 500;
+ private static final int NUMBER_OF_MESSAGES_PROCESSED = 100;
+ private static final long TIME_TAKEN = 100;
+ private static final long TOTAL_PAYLOAD_PROCESSED = 200;
+ private static final int PAYLOAD_SIZE = 300;
+
+ private static final Date START = new Date(0);
+ private static final Date END = new Date(START.getTime() + TIME_TAKEN);
+
+ private ParticipantResultFactory _participantResultFactory;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _participantResultFactory = new ParticipantResultFactory();
+ }
+
+ public void testCreateForProducer()
+ {
+ CreateProducerCommand command = new CreateProducerCommand();
+ setCommonCommandFields(command);
+
+ long producerStartDelay = 30;
+ command.setStartDelay(producerStartDelay);
+
+ int deliveryMode = DeliveryMode.PERSISTENT;
+ command.setDeliveryMode(deliveryMode);
+
+ int priority = 5;
+ command.setPriority(priority);
+
+ long producerInterval = 50;
+ command.setInterval(producerInterval);
+
+ long timeToLive = 60;
+ command.setTimeToLive(timeToLive);
+
+ ProducerParticipantResult result = _participantResultFactory.createForProducer(PARTICIPANT_NAME,
+ REGISTERED_CLIENT_NAME,
+ command,
+ NUMBER_OF_MESSAGES_PROCESSED,
+ PAYLOAD_SIZE,
+ TOTAL_PAYLOAD_PROCESSED,
+ START,
+ END);
+
+ assertCommonResultProperties(result);
+
+ assertEquals(deliveryMode, result.getDeliveryMode());
+ assertEquals(priority, result.getPriority());
+ assertEquals(producerInterval, result.getInterval());
+ assertEquals(producerStartDelay, result.getStartDelay());
+ assertEquals(timeToLive, result.getTimeToLive());
+ }
+
+ public void testCreateForConsumer()
+ {
+ CreateConsumerCommand command = new CreateConsumerCommand();
+ setCommonCommandFields(command);
+
+ boolean topic = true;
+ command.setTopic(topic);
+
+ boolean durable = true;
+ command.setDurableSubscription(durable);
+
+ boolean browsingSubscription = false;
+ command.setBrowsingSubscription(browsingSubscription);
+
+ String selector = "selector";
+ boolean isSelector = true;
+ command.setSelector(selector);
+
+ boolean noLocal = false;
+ command.setNoLocal(noLocal);
+
+ boolean synchronousConsumer = true;
+ command.setSynchronous(synchronousConsumer);
+
+ ConsumerParticipantResult result = _participantResultFactory.createForConsumer(PARTICIPANT_NAME,
+ REGISTERED_CLIENT_NAME,
+ command,
+ NUMBER_OF_MESSAGES_PROCESSED,
+ PAYLOAD_SIZE,
+ TOTAL_PAYLOAD_PROCESSED,
+ START,
+ END);
+
+ assertCommonResultProperties(result);
+
+ assertEquals(topic, result.isTopic());
+ assertEquals(durable, result.isDurableSubscription());
+ assertEquals(browsingSubscription, result.isBrowsingSubscription());
+ assertEquals(isSelector, result.isSelector());
+ assertEquals(noLocal, result.isNoLocal());
+ assertEquals(synchronousConsumer, result.isSynchronousConsumer());
+ }
+
+ public void testCreateForError()
+ {
+ String errorMessage = "error";
+ ParticipantResult result = _participantResultFactory.createForError(PARTICIPANT_NAME, REGISTERED_CLIENT_NAME, errorMessage);
+ assertEquals(PARTICIPANT_NAME, result.getParticipantName());
+ assertEquals(REGISTERED_CLIENT_NAME, result.getRegisteredClientName());
+ }
+
+
+ private void setCommonCommandFields(CreateParticpantCommand command)
+ {
+ command.setBatchSize(BATCH_SIZE);
+ command.setMaximumDuration(MAXIMUM_DURATION);
+ }
+
+
+ private void assertCommonResultProperties(ParticipantResult result)
+ {
+ assertEquals(PARTICIPANT_NAME, result.getParticipantName());
+ assertEquals(REGISTERED_CLIENT_NAME, result.getRegisteredClientName());
+ assertEquals(BATCH_SIZE, result.getBatchSize());
+ assertEquals(MAXIMUM_DURATION, result.getMaximumDuration());
+ assertEquals(TIME_TAKEN, result.getTimeTaken());
+ assertEquals(NUMBER_OF_MESSAGES_PROCESSED, result.getNumberOfMessagesProcessed());
+ assertEquals(TOTAL_PAYLOAD_PROCESSED, result.getTotalPayloadProcessed());
+ assertEquals(PAYLOAD_SIZE, result.getPayloadSize());
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java
new file mode 100644
index 0000000000..b30d5c1c7c
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java
@@ -0,0 +1,61 @@
+/*
+ * 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.disttest.client;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+
+public class ParticipantTestHelper
+{
+
+ public static void assertAtLeast(String message, final long minimumExpected, final long actual)
+ {
+ assertTrue(message + " " + actual, actual >= minimumExpected);
+ }
+
+ public static void assertExpectedResults(ParticipantResult result, String participantName, String registeredClientName, long expectedTestStartTime, Integer expectedNumberOfMessages, Integer expectedPayloadSize, Long expectedTotalPayloadProcessed, Long expectedMinimumExpectedDuration)
+ {
+ assertFalse(result.hasError());
+
+ assertEquals("unexpected participant name", participantName, result.getParticipantName());
+ assertEquals("unexpected client name", registeredClientName, result.getRegisteredClientName());
+
+ assertAtLeast("start time of result is too low", expectedTestStartTime, result.getStartInMillis());
+ assertAtLeast("end time of result should be after start time", result.getStartInMillis(), result.getEndInMillis());
+ if(expectedNumberOfMessages != null)
+ {
+ assertEquals("unexpected number of messages", expectedNumberOfMessages.intValue(), result.getNumberOfMessagesProcessed());
+ }
+ if (expectedPayloadSize != null)
+ {
+ assertEquals("unexpected payload size", expectedPayloadSize.intValue(), result.getPayloadSize());
+ }
+ if (expectedTotalPayloadProcessed != null)
+ {
+ assertEquals("unexpected total payload processed", expectedTotalPayloadProcessed.longValue(), result.getTotalPayloadProcessed());
+ }
+ if(expectedMinimumExpectedDuration != null)
+ {
+ assertAtLeast("participant did not take a sufficient length of time.", expectedMinimumExpectedDuration, result.getTimeTaken());
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java
new file mode 100644
index 0000000000..3852948201
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.disttest.client;
+
+import static org.apache.qpid.disttest.client.ParticipantTestHelper.assertExpectedResults;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.mockito.InOrder;
+
+public class ProducerParticipantTest extends TestCase
+{
+ private ProducerParticipant _producer;
+
+ private static final String SESSION_NAME1 = "SESSION1";
+ private static final String PARTICIPANT_NAME1 = "PARTICIPANT_NAME1";
+
+ private static final String CLIENT_NAME = "CLIENT_NAME";
+ private static final int PAYLOAD_SIZE_PER_MESSAGE = 1024;
+
+
+ private final Message _mockMessage = mock(Message.class);
+ private final CreateProducerCommand _command = new CreateProducerCommand();
+ private ClientJmsDelegate _delegate;
+ private InOrder _inOrder;
+
+ /** used to check start/end time of results */
+ private long _testStartTime;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _delegate = mock(ClientJmsDelegate.class);
+ _inOrder = inOrder(_delegate);
+
+ _command.setSessionName(SESSION_NAME1);
+ _command.setParticipantName(PARTICIPANT_NAME1);
+
+ when(_delegate.sendNextMessage(isA(CreateProducerCommand.class))).thenReturn(_mockMessage);
+ when(_delegate.calculatePayloadSizeFrom(_mockMessage)).thenReturn(PAYLOAD_SIZE_PER_MESSAGE);
+
+ _producer = new ProducerParticipant(_delegate, _command);
+
+ _testStartTime = System.currentTimeMillis();
+ }
+
+ public void testStartDelay() throws Exception
+ {
+ final long delay = 100;
+ int numberOfMessages = 1;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+
+ _command.setStartDelay(delay);
+ _command.setNumberOfMessages(numberOfMessages);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+
+ long expectedPublishedStartTime = _testStartTime + delay;
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, expectedPublishedStartTime, numberOfMessages, PAYLOAD_SIZE_PER_MESSAGE, totalPayloadSize, null);
+ }
+
+
+ public void testNoMessagesToSend() throws Exception
+ {
+ _command.setNumberOfMessages(0);
+ _command.setMaximumDuration(0);
+
+ try
+ {
+ _producer.doIt(CLIENT_NAME);
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ assertEquals("number of messages and duration cannot both be zero", e.getMessage());
+ }
+ }
+
+ public void testOneMessageToSend() throws Exception
+ {
+ int batchSize = 1;
+ int numberOfMessages = 1;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+ int deliveryMode = DeliveryMode.PERSISTENT;
+
+ _command.setNumberOfMessages(numberOfMessages);
+ _command.setBatchSize(batchSize);
+ _command.setDeliveryMode(deliveryMode);
+
+ ParticipantResult result = (ParticipantResult) _producer.doIt(CLIENT_NAME);
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, PAYLOAD_SIZE_PER_MESSAGE, totalPayloadSize, null);
+
+ _inOrder.verify(_delegate).sendNextMessage(isA(CreateProducerCommand.class));
+ _inOrder.verify(_delegate).calculatePayloadSizeFrom(_mockMessage);
+ _inOrder.verify(_delegate).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+
+ }
+
+ public void testSendMessagesForDuration() throws Exception
+ {
+ final long duration = 100;
+ _command.setMaximumDuration(duration);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, null, PAYLOAD_SIZE_PER_MESSAGE, null, duration);
+
+ verify(_delegate, atLeastOnce()).sendNextMessage(isA(CreateProducerCommand.class));
+ verify(_delegate, atLeastOnce()).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, atLeastOnce()).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testSendMessageBatches() throws Exception
+ {
+ final int numberOfMessages = 10;
+ final int expectedNumberOfCommits = 4; // one for each batch of 3 messages, plus one more at the end of the test for the tenth msg.
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+
+ _command.setNumberOfMessages(numberOfMessages);
+ _command.setBatchSize(3);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, PAYLOAD_SIZE_PER_MESSAGE, totalPayloadSize, null);
+
+ verify(_delegate, times(numberOfMessages)).sendNextMessage(isA(CreateProducerCommand.class));
+ verify(_delegate, times(numberOfMessages)).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, times(expectedNumberOfCommits)).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testSendMessageWithPublishInterval() throws Exception
+ {
+ final int batchSize = 3;
+ final long publishInterval = 100;
+ int numberOfMessages = 10;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+
+ final long expectedTimeToRunTest = batchSize * publishInterval;
+
+ _command.setNumberOfMessages(numberOfMessages);
+ _command.setBatchSize(batchSize);
+ _command.setInterval(publishInterval);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, null, totalPayloadSize, expectedTimeToRunTest);
+
+ verify(_delegate, times(numberOfMessages)).sendNextMessage(isA(CreateProducerCommand.class));
+ verify(_delegate, times(numberOfMessages)).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, times(4)).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testSendMessageWithVaryingPayloadSize() throws Exception
+ {
+ int numberOfMessages = 3;
+
+ int firstPayloadSize = PAYLOAD_SIZE_PER_MESSAGE;
+ int secondPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * 2;
+ int thirdPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * 4;
+
+ final long totalPayloadSize = firstPayloadSize + secondPayloadSize + thirdPayloadSize;
+
+ when(_delegate.calculatePayloadSizeFrom(_mockMessage)).thenReturn(firstPayloadSize, secondPayloadSize, thirdPayloadSize);
+
+ _command.setNumberOfMessages(numberOfMessages);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+
+ final int expectedPayloadResultPayloadSize = 0;
+ assertExpectedResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime, numberOfMessages, expectedPayloadResultPayloadSize, totalPayloadSize, null);
+
+ verify(_delegate, times(numberOfMessages)).sendNextMessage(isA(CreateProducerCommand.class));
+ verify(_delegate, times(numberOfMessages)).calculatePayloadSizeFrom(_mockMessage);
+ verify(_delegate, times(numberOfMessages)).commitOrAcknowledgeMessage(_mockMessage, SESSION_NAME1);
+ }
+
+ public void testReleaseResources()
+ {
+ _producer.releaseResources();
+ verify(_delegate).closeTestProducer(PARTICIPANT_NAME1);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java
new file mode 100644
index 0000000000..75a634ba54
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.disttest.client.property;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.client.property.ListPropertyValue;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+
+public class ListPropertyValueTest extends TestCase
+{
+ private ListPropertyValue _generator;
+ private List<PropertyValue> _items;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _generator = new ListPropertyValue();
+ _items = new ArrayList<PropertyValue>();
+ _items.add(new SimplePropertyValue(new Integer(1)));
+ _items.add(new SimplePropertyValue(new Double(2.1)));
+ _items.add(new SimplePropertyValue(new Boolean(true)));
+ ListPropertyValue innerList = new ListPropertyValue();
+ List<PropertyValue> innerListItems = new ArrayList<PropertyValue>();
+ innerListItems.add(new SimplePropertyValue("test"));
+ innerListItems.add(new SimplePropertyValue(new Integer(2)));
+ innerList.setItems(innerListItems);
+ _items.add(innerList);
+ _generator.setItems(_items);
+ }
+
+ public void testGetItems()
+ {
+ List<? extends Object> items = _generator.getItems();
+ assertEquals("Unexpected list items", _items, items);
+ }
+
+ public void testGetValue()
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ assertEquals("Unexpected first item", new Integer(1), _generator.getValue());
+ assertEquals("Unexpected second item", new Double(2.1), _generator.getValue());
+ assertEquals("Unexpected third item", new Boolean(true), _generator.getValue());
+ if (i == 0)
+ {
+ assertEquals("Unexpected forth item", "test", _generator.getValue());
+ }
+ else
+ {
+ assertEquals("Unexpected forth item", new Integer(2), _generator.getValue());
+ }
+ }
+ }
+
+ public void testNonCyclicGetValue()
+ {
+ _generator.setCyclic(false);
+ assertFalse("Generator should not be cyclic", _generator.isCyclic());
+ assertEquals("Unexpected first item", new Integer(1), _generator.getValue());
+ assertEquals("Unexpected second item", new Double(2.1), _generator.getValue());
+ assertEquals("Unexpected third item", new Boolean(true), _generator.getValue());
+ assertEquals("Unexpected forth item", "test", _generator.getValue());
+ assertEquals("Unexpected fifth item", new Integer(2), _generator.getValue());
+ assertEquals("Unexpected sixs item", "test", _generator.getValue());
+ assertEquals("Unexpected sevens item", new Integer(2), _generator.getValue());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java
new file mode 100644
index 0000000000..2d560163c2
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.disttest.client.property;
+
+import junit.framework.TestCase;
+
+public class PropertyValueFactoryTest extends TestCase
+{
+ private PropertyValueFactory _factory;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _factory = new PropertyValueFactory();
+ }
+
+ public void testCreateListPropertyValue()
+ {
+ PropertyValue propertyValue = _factory.createPropertyValue("list");
+ assertNotNull("List generator is not created", propertyValue);
+ assertTrue("Unexpected type of list generator", propertyValue instanceof ListPropertyValue);
+ }
+
+ public void testCreateRangePropertyValue()
+ {
+ PropertyValue propertyValue = _factory.createPropertyValue("range");
+ assertNotNull("Range generator is not created", propertyValue);
+ assertTrue("Unexpected type of range generator", propertyValue instanceof RangePropertyValue);
+ }
+
+ public void testCreateRandomPropertyValue()
+ {
+ PropertyValue propertyValue = _factory.createPropertyValue("random");
+ assertNotNull("Random generator is not created", propertyValue);
+ assertTrue("Unexpected type of range generator", propertyValue instanceof RandomPropertyValue);
+ }
+
+ public void testCreateSimplePropertyValue()
+ {
+ PropertyValue propertyValue = _factory.createPropertyValue("simple");
+ assertNotNull("Simple property value is not created", propertyValue);
+ assertTrue("Unexpected type of property value", propertyValue instanceof SimplePropertyValue);
+ }
+
+ public void testCreateNonExistingPropertyValue()
+ {
+ try
+ {
+ _factory.createPropertyValue("nonExisting");
+ fail("Non existing property value should not be created");
+ }
+ catch (Exception e)
+ {
+ // pass
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java
new file mode 100644
index 0000000000..bd5de3e370
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.disttest.client.property;
+
+import org.apache.qpid.disttest.client.property.RandomPropertyValue;
+
+import junit.framework.TestCase;
+
+public class RandomPropertyValueTest extends TestCase
+{
+ private RandomPropertyValue _generator;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _generator = new RandomPropertyValue();
+ _generator.setUpper(20.0);
+ _generator.setLower(10.0);
+ _generator.setType("double");
+ }
+
+ public void testGetters()
+ {
+ assertEquals("Unexpected upper boundary", new Double(20.0), _generator.getUpper());
+ assertEquals("Unexpected lower boundary", new Double(10.0), _generator.getLower());
+ assertEquals("Unexpected type", "double", _generator.getType());
+ }
+
+ public void testGetValue()
+ {
+ Object value = _generator.getValue();
+ assertTrue("Unexpected type", value instanceof Double);
+ assertTrue("Unexpected value", ((Double) value).doubleValue() >= 10.0
+ && ((Double) value).doubleValue() <= 20.0);
+ }
+
+ public void testGetValueInt()
+ {
+ _generator.setType("int");
+ Object value = _generator.getValue();
+ assertTrue("Unexpected type", value instanceof Integer);
+ assertTrue("Unexpected value", ((Integer) value).intValue() >= 10 && ((Integer) value).intValue() <= 20);
+ }
+
+ public void testGetValueLong()
+ {
+ _generator.setType("long");
+ Object value = _generator.getValue();
+ assertTrue("Unexpected type", value instanceof Long);
+ assertTrue("Unexpected value", ((Long) value).longValue() >= 10 && ((Long) value).longValue() <= 20);
+ }
+
+ public void testGetValueFloat()
+ {
+ _generator.setType("float");
+ Object value = _generator.getValue();
+ assertTrue("Unexpected type", value instanceof Float);
+ assertTrue("Unexpected value", ((Float) value).floatValue() >= 10.0 && ((Float) value).floatValue() <= 20.0);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java
new file mode 100644
index 0000000000..91791c9d55
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.disttest.client.property;
+
+import org.apache.qpid.disttest.client.property.RangePropertyValue;
+
+import junit.framework.TestCase;
+
+public class RangePropertyValueTest extends TestCase
+{
+ private RangePropertyValue _generator;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _generator = new RangePropertyValue();
+ _generator.setUpper(10.0);
+ _generator.setLower(0.0);
+ _generator.setStep(2.0);
+ _generator.setType("double");
+ }
+
+ public void testGetters()
+ {
+ assertEquals("Unexpected upper boundary", new Double(10.0), _generator.getUpper());
+ assertEquals("Unexpected lower boundary", new Double(0.0), _generator.getLower());
+ assertEquals("Unexpected step", new Double(2.0), _generator.getStep());
+ assertEquals("Unexpected type", "double", _generator.getType());
+ assertTrue("Unexpected cyclic", _generator.isCyclic());
+ }
+
+ public void testGetValue()
+ {
+ double[] expected = { 0.0, 2.0, 4.0, 6.0, 8.0, 10.0 };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Double);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+
+ public void testGetValueNonCyclic()
+ {
+ _generator.setCyclic(false);
+ double[] expected = { 0.0, 2.0, 4.0, 6.0, 8.0, 10.0 };
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Double);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertEquals("Unexpected value ", expected[expected.length - 1], value);
+ }
+ }
+
+ public void testGetValueInt()
+ {
+ _generator.setType("int");
+ int[] expected = { 0, 2, 4, 6, 8, 10 };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Integer);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+
+ public void testGetValueByte()
+ {
+ _generator.setType("byte");
+ byte[] expected = { 0, 2, 4, 6, 8, 10 };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Byte);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+
+ public void testGetValueLong()
+ {
+ _generator.setType("long");
+ long[] expected = { 0, 2, 4, 6, 8, 10 };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Long);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+
+ public void testGetValueShort()
+ {
+ _generator.setType("short");
+ short[] expected = { 0, 2, 4, 6, 8, 10 };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Short);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+
+ public void testGetValueFloat()
+ {
+ _generator.setType("float");
+ float[] expected = { 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f };
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < expected.length; i++)
+ {
+ Object value = _generator.getValue();
+ assertTrue("Should be Double", value instanceof Float);
+ assertEquals("Unexpected value ", expected[i], value);
+ }
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java
new file mode 100644
index 0000000000..a347d866c7
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.disttest.client.property;
+
+import junit.framework.TestCase;
+
+public class SimplePropertyValueTest extends TestCase
+{
+ public void testGetValue()
+ {
+ SimplePropertyValue value = new SimplePropertyValue(new Integer(1));
+ assertEquals("Unexpected value", new Integer(1), value.getValue());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java
new file mode 100644
index 0000000000..2c161012a9
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.disttest.controller;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+
+public class ClientRegistryTest extends TestCase
+{
+ private static final String CLIENT1_REGISTERED_NAME = "CLIENT1_REGISTERED_NAME";
+
+ private ClientRegistry _clientRegistry = new ClientRegistry();
+
+ public void testRegisterClient()
+ {
+ assertEquals(0, _clientRegistry.getClients().size());
+
+ _clientRegistry.registerClient(CLIENT1_REGISTERED_NAME);
+ assertEquals(1, _clientRegistry.getClients().size());
+
+ }
+
+ public void testRejectsDuplicateClientNames()
+ {
+ _clientRegistry.registerClient(CLIENT1_REGISTERED_NAME);
+ try
+ {
+ _clientRegistry.registerClient(CLIENT1_REGISTERED_NAME);
+ fail("Should have thrown an exception");
+ }
+ catch (final DistributedTestException e)
+ {
+ // pass
+ }
+ }
+
+
+
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java
new file mode 100644
index 0000000000..c119656afd
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java
@@ -0,0 +1,253 @@
+/*
+ * 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.disttest.controller;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.controller.config.TestInstance;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class ControllerTest extends TestCase
+{
+ private static final String CLIENT1_REGISTERED_NAME = "client-uid1";
+ private static final String CLIENT2_REGISTERED_NAME = "client-uid2";
+
+ private static final int DELAY = 100;
+ private static final long COMMAND_RESPONSE_TIMEOUT = 1000;
+ private static final long REGISTRATION_TIMEOUT = 1000;
+
+ private Controller _controller;
+ private ControllerJmsDelegate _respondingJmsDelegate;
+ private TestRunner _testRunner;
+ private ClientRegistry _clientRegistry;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _respondingJmsDelegate = mock(ControllerJmsDelegate.class);
+ _controller = new Controller(_respondingJmsDelegate, REGISTRATION_TIMEOUT, COMMAND_RESPONSE_TIMEOUT);
+ _testRunner = mock(TestRunner.class);
+ _clientRegistry = mock(ClientRegistry.class);
+
+ Config configWithOneClient = createMockConfig(1);
+ _controller.setConfig(configWithOneClient);
+ _controller.setClientRegistry(_clientRegistry);
+ _controller.setTestRunnerFactory(createTestFactoryReturningMock());
+
+ doAnswer(new Answer<Void>()
+ {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable
+ {
+ final String clientName = (String)invocation.getArguments()[0];
+ final Command command = (Command)invocation.getArguments()[1];
+ _controller.processStopClientResponse(new Response(clientName, command.getType()));
+ return null;
+ }
+ }).when(_respondingJmsDelegate).sendCommandToClient(anyString(), isA(Command.class));
+ }
+
+
+ public void testControllerRejectsEmptyConfiguration()
+ {
+ Config configWithZeroClients = createMockConfig(0);
+
+ try
+ {
+ _controller.setConfig(configWithZeroClients);
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testControllerRequiresOneClientRegistration()
+ {
+ Config configWithOneClient = createMockConfig(1);
+
+ _controller.setConfig(configWithOneClient);
+ registerClientAndAwait(CLIENT1_REGISTERED_NAME);
+ }
+
+ public void testControllerReceivesTwoExpectedClientRegistrations()
+ {
+ Config configWithTwoClients = createMockConfig(2);
+ _controller.setConfig(configWithTwoClients);
+
+ registerClientLater(_controller, CLIENT1_REGISTERED_NAME);
+ registerClientLater(_controller, CLIENT2_REGISTERED_NAME);
+ _controller.awaitClientRegistrations();
+ }
+
+ public void testControllerDoesntReceiveAnyRegistrations()
+ {
+ try
+ {
+ _controller.awaitClientRegistrations();
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testControllerDoesntReceiveTwoExpectedClientRegistrations()
+ {
+ Config configWithTwoClients = createMockConfig(2);
+ _controller.setConfig(configWithTwoClients);
+
+ registerClientLater(_controller, CLIENT1_REGISTERED_NAME); // only receives one out of two expected registrations
+ try
+ {
+ _controller.awaitClientRegistrations();
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testRegisterClient()
+ {
+ RegisterClientCommand command = new RegisterClientCommand(CLIENT1_REGISTERED_NAME, "dummy");
+ _controller.registerClient(command);
+
+ verify(_clientRegistry).registerClient(CLIENT1_REGISTERED_NAME);
+ verify(_respondingJmsDelegate).registerClient(command);
+
+ }
+
+ public void testControllerSendsClientStopCommandToClient()
+ {
+ when(_clientRegistry.getClients()).thenReturn(Collections.singleton(CLIENT1_REGISTERED_NAME));
+
+ _controller.stopAllRegisteredClients();
+
+ verify(_respondingJmsDelegate).sendCommandToClient(eq(CLIENT1_REGISTERED_NAME), isA(StopClientCommand.class));
+ }
+
+ public void testRunAllTests()
+ {
+ Config config = createSimpleConfig();
+ _controller.setConfig(config);
+
+ TestResult testResult = new TestResult("test1");
+
+ when(_testRunner.run()).thenReturn(testResult);
+
+ ResultsForAllTests results = _controller.runAllTests();
+
+ List<ITestResult> testResults = results.getTestResults();
+ assertEquals(1, testResults.size());
+ assertSame(testResult, testResults.get(0));
+
+ verify(_testRunner).run();
+ }
+
+ private Config createSimpleConfig()
+ {
+ Config config = mock(Config.class);
+ TestInstance testInstance = mock(TestInstance.class);
+
+ List<TestInstance> testInstances = Arrays.asList(testInstance);
+
+ when(config.getTests()).thenReturn(testInstances);
+ when(config.getTotalNumberOfClients()).thenReturn(1); // necessary otherwise controller rejects "invalid" config
+
+ return config;
+ }
+
+ private void doLater(TimerTask task, long delayInMillis)
+ {
+ Timer timer = new Timer();
+ timer.schedule(task, delayInMillis);
+ }
+
+ private Config createMockConfig(int numberOfClients)
+ {
+ Config config = mock(Config.class);
+ when(config.getTotalNumberOfClients()).thenReturn(numberOfClients);
+ return config;
+ }
+
+ private void registerClientAndAwait(String... clientNames)
+ {
+ for (String clientName : clientNames)
+ {
+ registerClientLater(_controller, clientName);
+ }
+ _controller.awaitClientRegistrations();
+ }
+
+ private void registerClientLater(final Controller controller, final String clientName)
+ {
+ doLater(new TimerTask()
+ {
+ @Override
+ public void run()
+ {
+ controller.registerClient(new RegisterClientCommand(clientName, "dummy"));
+ }
+ }, DELAY);
+ }
+
+ private TestRunnerFactory createTestFactoryReturningMock()
+ {
+ TestRunnerFactory testRunnerFactory = mock(TestRunnerFactory.class);
+
+ when(testRunnerFactory.createTestRunner(
+ isA(ParticipatingClients.class),
+ isA(TestInstance.class),
+ isA(ControllerJmsDelegate.class),
+ isA(Long.class),
+ isA(Long.class)))
+ .thenReturn(_testRunner);
+
+ return testRunnerFactory;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java
new file mode 100644
index 0000000000..284db38f44
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.disttest.controller;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class ParticipatingClientsTest extends TestCase
+{
+ private static final String CLIENT1_CONFIGURED_NAME = "CLIENT1_CONFIGURED_NAME";
+ private static final String CLIENT2_CONFIGURED_NAME = "CLIENT2_CONFIGURED_NAME";
+
+ private static final String CLIENT1_REGISTERED_NAME = "CLIENT1_REGISTERED_NAME";
+ private static final String CLIENT2_REGISTERED_NAME = "CLIENT2_REGISTERED_NAME";
+ private static final String CLIENT3_REGISTERED_NAME = "CLIENT3_REGISTERED_NAME";
+ private ClientRegistry _clientRegistry;
+ private List<String> _configuredClientNamesForTest;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _clientRegistry = mock(ClientRegistry.class);
+ }
+
+ public void testTooFewRegisteredClientsForTest()
+ {
+ _configuredClientNamesForTest = Arrays.asList(CLIENT1_CONFIGURED_NAME, CLIENT2_CONFIGURED_NAME);
+ when(_clientRegistry.getClients()).thenReturn(Arrays.asList(CLIENT1_REGISTERED_NAME));
+
+ try
+ {
+ new ParticipatingClients(_clientRegistry, _configuredClientNamesForTest);
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // PASS
+ }
+
+ }
+
+
+ public void testSelectOneClientFromPoolOfOne()
+ {
+ _configuredClientNamesForTest = Arrays.asList(CLIENT1_CONFIGURED_NAME);
+ when(_clientRegistry.getClients()).thenReturn(Arrays.asList(CLIENT1_REGISTERED_NAME));
+
+ ParticipatingClients clients = new ParticipatingClients(_clientRegistry, _configuredClientNamesForTest);
+ assertBothWays(clients, CLIENT1_REGISTERED_NAME, CLIENT1_CONFIGURED_NAME);
+ }
+
+ public void testSelectTwoClientFromPoolOfMany()
+ {
+ _configuredClientNamesForTest = Arrays.asList(CLIENT1_CONFIGURED_NAME, CLIENT2_CONFIGURED_NAME);
+ when(_clientRegistry.getClients()).thenReturn(Arrays.asList(CLIENT1_REGISTERED_NAME, CLIENT2_REGISTERED_NAME, CLIENT3_REGISTERED_NAME));
+
+ ParticipatingClients clients = new ParticipatingClients(_clientRegistry, _configuredClientNamesForTest);
+
+ assertBothWays(clients, CLIENT1_REGISTERED_NAME, CLIENT1_CONFIGURED_NAME);
+ assertBothWays(clients, CLIENT2_REGISTERED_NAME, CLIENT2_CONFIGURED_NAME);
+ }
+
+ public void testGetUnrecognisedConfiguredName()
+ {
+ _configuredClientNamesForTest = Arrays.asList(CLIENT1_CONFIGURED_NAME);
+ when(_clientRegistry.getClients()).thenReturn(Arrays.asList(CLIENT1_REGISTERED_NAME));
+
+ ParticipatingClients clients = new ParticipatingClients(_clientRegistry, _configuredClientNamesForTest);
+
+ testUnrecognisedClientConfiguredName(clients, "unknown");
+ testUnrecognisedClientRegisteredName(clients, "unknown");
+ }
+
+ public void testGetRegisteredClientNames()
+ {
+ _configuredClientNamesForTest = Arrays.asList(CLIENT1_CONFIGURED_NAME);
+ List<String> registeredNames = Arrays.asList(CLIENT1_REGISTERED_NAME);
+ when(_clientRegistry.getClients()).thenReturn(registeredNames);
+
+ ParticipatingClients clients = new ParticipatingClients(_clientRegistry, _configuredClientNamesForTest);
+
+ Collection<String> registeredParticipatingNames = clients.getRegisteredNames();
+ assertEquals(1, registeredParticipatingNames.size());
+ assertTrue(registeredParticipatingNames.contains(CLIENT1_REGISTERED_NAME));
+ }
+
+ private void testUnrecognisedClientConfiguredName(ParticipatingClients clients, String unrecognisedClientConfiguredName)
+ {
+ try
+ {
+ clients.getRegisteredNameFromConfiguredName(unrecognisedClientConfiguredName);
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // PASS
+ }
+ }
+
+ private void testUnrecognisedClientRegisteredName(ParticipatingClients clients, String unrecognisedClientRegisteredName)
+ {
+ try
+ {
+ clients.getConfiguredNameFromRegisteredName(unrecognisedClientRegisteredName);
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // PASS
+ }
+ }
+
+ private void assertBothWays(ParticipatingClients clients, String registeredName, String configuredName)
+ {
+ assertEquals(registeredName, clients.getRegisteredNameFromConfiguredName(configuredName));
+ assertEquals(configuredName, clients.getConfiguredNameFromRegisteredName(registeredName));
+ }
+
+
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java
new file mode 100644
index 0000000000..ffd41049be
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.disttest.controller;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+import org.apache.qpid.disttest.controller.config.TestInstance;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class TestRunnerTest extends TestCase
+{
+ private static final String TEST_NAME = "TEST_NAME";
+ private static final int ITERATION_NUMBER = 1;
+
+ private static final String CLIENT1_REGISTERED_NAME = "client-uid1";
+ private static final String CLIENT1_CONFIGURED_NAME = "client1";
+
+ private static final long COMMAND_RESPONSE_TIMEOUT = 1000;
+ private static final long TEST_RESULT_TIMEOUT = 2000;
+ private static final long DELAY = 100;
+
+ private TestRunner _testRunner;
+ private TestInstance _testInstance;
+ private ControllerJmsDelegate _respondingJmsDelegate;
+ private ParticipatingClients _participatingClients;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _respondingJmsDelegate = mock(ControllerJmsDelegate.class);
+
+ _participatingClients = mock(ParticipatingClients.class);
+ when(_participatingClients.getRegisteredNameFromConfiguredName(CLIENT1_CONFIGURED_NAME)).thenReturn(CLIENT1_REGISTERED_NAME);
+ when(_participatingClients.getConfiguredNameFromRegisteredName(CLIENT1_REGISTERED_NAME)).thenReturn(CLIENT1_CONFIGURED_NAME);
+ when(_participatingClients.getRegisteredNames()).thenReturn(Collections.singleton(CLIENT1_REGISTERED_NAME));
+
+ doAnswer(new Answer<Void>()
+ {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable
+ {
+ final String clientName = (String)invocation.getArguments()[0];
+ final Command command = (Command)invocation.getArguments()[1];
+ _testRunner.processCommandResponse(new Response(clientName, command.getType()));
+ return null;
+ }
+ }).when(_respondingJmsDelegate).sendCommandToClient(anyString(), isA(Command.class));
+ }
+
+ public void testSendConnectionCommandToClient()
+ {
+ _testInstance = createTestInstanceWithConnection();
+
+ _testRunner = new TestRunner(_participatingClients, _testInstance , _respondingJmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+ _testRunner.sendTestSetupCommands();
+
+ verify(_respondingJmsDelegate).sendCommandToClient(eq(CLIENT1_REGISTERED_NAME), isA(CreateConnectionCommand.class));
+ }
+
+ public void testSendCommandToAllParticipatingClients()
+ {
+ _testRunner = new TestRunner(_participatingClients, mock(TestInstance.class), _respondingJmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+
+ StartTestCommand startTestCommand = new StartTestCommand();
+ _testRunner.sendCommandToParticipatingClients(startTestCommand);
+
+ verify(_respondingJmsDelegate).sendCommandToClient(CLIENT1_REGISTERED_NAME, startTestCommand);
+ }
+
+ public void testWaitsForCommandResponses()
+ {
+ _testInstance = createTestInstanceWithConnection();
+ _testRunner = new TestRunner(_participatingClients, _testInstance , _respondingJmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+
+ _testRunner.sendTestSetupCommands();
+
+ _testRunner.awaitCommandResponses();
+ }
+
+ public void testClientFailsToSendCommandResponseWithinTimeout()
+ {
+ ControllerJmsDelegate jmsDelegate = mock(ControllerJmsDelegate.class);
+
+ _testInstance = createTestInstanceWithConnection();
+ _testRunner = new TestRunner(_participatingClients, _testInstance , jmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+
+ _testRunner.sendTestSetupCommands();
+ // we don't call sendCommandResponseLater so controller should time out
+
+ try
+ {
+ _testRunner.awaitCommandResponses();
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testCreateAndDeleteQueues()
+ {
+ _testInstance = mock(TestInstance.class);
+ List<QueueConfig> queues = mock(List.class);
+ when(_testInstance.getQueues()).thenReturn(queues);
+
+ _testRunner = new TestRunner(_participatingClients, _testInstance, _respondingJmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+
+ _testRunner.createQueues();
+ verify(_respondingJmsDelegate).createQueues(queues);
+
+ _testRunner.deleteQueues();
+ verify(_respondingJmsDelegate).deleteQueues(queues);
+ }
+
+ public void testRun()
+ {
+ _testInstance = createTestInstanceWithOneParticipant();
+ _testRunner = new TestRunner(_participatingClients, _testInstance , _respondingJmsDelegate, COMMAND_RESPONSE_TIMEOUT, TEST_RESULT_TIMEOUT);
+
+ ParticipantResult incomingParticipantResult = new ParticipantResult();
+ incomingParticipantResult.setRegisteredClientName(CLIENT1_REGISTERED_NAME);
+ sendTestResultsLater(_testRunner, incomingParticipantResult);
+
+ TestResult results = _testRunner.run();
+
+ verify(_respondingJmsDelegate).addCommandListener(isA(TestRunner.TestCommandResponseListener.class));
+ verify(_respondingJmsDelegate).addCommandListener(isA(TestRunner.ParticipantResultListener.class));
+
+ verify(_respondingJmsDelegate).createQueues(isA(List.class));
+
+ verify(_respondingJmsDelegate).sendCommandToClient(eq(CLIENT1_REGISTERED_NAME), isA(StartTestCommand.class));
+ verify(_respondingJmsDelegate).sendCommandToClient(eq(CLIENT1_REGISTERED_NAME), isA(NoOpCommand.class));
+ verify(_respondingJmsDelegate).sendCommandToClient(eq(CLIENT1_REGISTERED_NAME), isA(TearDownTestCommand.class));
+
+ verify(_respondingJmsDelegate).deleteQueues(isA(List.class));
+
+ verify(_respondingJmsDelegate).removeCommandListener(isA(TestRunner.ParticipantResultListener.class));
+ verify(_respondingJmsDelegate).removeCommandListener(isA(TestRunner.TestCommandResponseListener.class));
+
+ List<ParticipantResult> participantResults = results.getParticipantResults();
+ assertEquals(1, participantResults.size());
+ ParticipantResult resultingParticipantResult = participantResults.get(0);
+
+ assertResultHasCorrectTestDetails(resultingParticipantResult);
+ }
+
+ private void assertResultHasCorrectTestDetails(ParticipantResult resultingParticipantResult)
+ {
+ assertEquals("Test runner should have set configured name when it received participant results",
+ CLIENT1_CONFIGURED_NAME, resultingParticipantResult.getConfiguredClientName());
+ assertEquals("Test runner should have set test name when it received participant results",
+ TEST_NAME, resultingParticipantResult.getTestName());
+ assertEquals("Test runner should have set test iteration number when it received participant results",
+ ITERATION_NUMBER, resultingParticipantResult.getIterationNumber());
+ }
+
+
+ private TestInstance createTestInstanceWithOneParticipant()
+ {
+ TestInstance testInstance = mock(TestInstance.class);
+
+ List<CommandForClient> commands = Arrays.asList(
+ new CommandForClient(CLIENT1_CONFIGURED_NAME, new NoOpCommand()));
+
+ when(testInstance.createCommands()).thenReturn(commands);
+
+ when(testInstance.getTotalNumberOfParticipants()).thenReturn(1);
+
+ when(testInstance.getName()).thenReturn(TEST_NAME);
+
+ List<QueueConfig> queues = mock(List.class);
+ when(testInstance.getQueues()).thenReturn(queues);
+
+ when(testInstance.getIterationNumber()).thenReturn(ITERATION_NUMBER);
+
+ return testInstance;
+ }
+
+ private TestInstance createTestInstanceWithConnection()
+ {
+ TestInstance testInstance = mock(TestInstance.class);
+
+ List<CommandForClient> commands = Arrays.asList(
+ new CommandForClient(CLIENT1_CONFIGURED_NAME, new CreateConnectionCommand("conn1", "factory")));
+
+ when(testInstance.createCommands()).thenReturn(commands);
+
+ return testInstance;
+ }
+
+ private void sendTestResultsLater(final TestRunner runner, final ParticipantResult result)
+ {
+ doLater(new TimerTask()
+ {
+ @Override
+ public void run()
+ {
+ runner.processParticipantResult(result);
+ }
+ }, DELAY);
+ }
+
+ private void doLater(TimerTask task, long delayInMillis)
+ {
+ Timer timer = new Timer();
+ timer.schedule(task, delayInMillis);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java
new file mode 100644
index 0000000000..d4af439dea
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.assertCommandForClient;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+
+public class ClientConfigTest extends TestCase
+{
+ private static final String CLIENT1 = "client1";
+
+ public void testClientConfigHasZeroArgConstructorForGson()
+ {
+ ClientConfig c = new ClientConfig();
+ assertNotNull(c);
+ }
+
+ public void testCreateCommands()
+ {
+ ClientConfig clientConfig = createClientConfigWithConnectionConfigReturningChildCommands();
+
+ List<CommandForClient> commands = clientConfig.createCommands();
+ assertEquals(2, commands.size());
+
+ assertCommandForClient(commands, 0, CLIENT1, NoOpCommand.class);
+ assertCommandForClient(commands, 1, CLIENT1, NoOpCommand.class);
+ }
+
+ public void testCreateCommandsForMessageProvider()
+ {
+ ClientConfig clientConfig = createClientConfigWithMessageProviderConfigReturningCommands();
+
+ List<CommandForClient> commands = clientConfig.createCommands();
+ assertEquals(1, commands.size());
+
+ assertCommandForClient(commands, 0, CLIENT1, CreateMessageProviderCommand.class);
+ }
+
+ public void testGetTotalNumberOfParticipants()
+ {
+ ClientConfig clientConfig = createClientConfigWithTwoParticipants();
+ assertEquals(2, clientConfig.getTotalNumberOfParticipants());
+ }
+
+ private ClientConfig createClientConfigWithConnectionConfigReturningChildCommands()
+ {
+ ConnectionConfig connectionConfig = mock(ConnectionConfig.class);
+
+ List<Command> commands = Arrays.asList((Command)new NoOpCommand(), (Command)new NoOpCommand());
+ when(connectionConfig.createCommands()).thenReturn(commands);
+
+ return new ClientConfig(CLIENT1, connectionConfig);
+ }
+
+ private ClientConfig createClientConfigWithMessageProviderConfigReturningCommands()
+ {
+ Map<String, PropertyValue> messageProperties = new HashMap<String, PropertyValue>();
+ messageProperties.put("test", new SimplePropertyValue("testValue"));
+ MessageProviderConfig config = new MessageProviderConfig("test", messageProperties);
+
+ List<MessageProviderConfig> providerConfigs = new ArrayList<MessageProviderConfig>();
+ providerConfigs.add(config);
+
+ return new ClientConfig(CLIENT1, new ArrayList<ConnectionConfig>(), providerConfigs);
+ }
+
+ private ClientConfig createClientConfigWithTwoParticipants()
+ {
+ ConnectionConfig connectionConfig1 = mock(ConnectionConfig.class);
+ ConnectionConfig connectionConfig2 = mock(ConnectionConfig.class);
+
+ when(connectionConfig1.getTotalNumberOfParticipants()).thenReturn(1);
+ when(connectionConfig2.getTotalNumberOfParticipants()).thenReturn(1);
+
+ ClientConfig clientConfig = new ClientConfig(CLIENT1, connectionConfig1, connectionConfig2);
+ return clientConfig;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java
new file mode 100644
index 0000000000..af9ec28db0
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.io.Reader;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.ConfigFileHelper;
+import org.apache.qpid.disttest.client.MessageProvider;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.controller.CommandForClient;
+
+public class ConfigReaderTest extends TestCase
+{
+ private Config _config;
+
+ @Override
+ protected void setUp()
+ {
+ ConfigReader configReader = new ConfigReader();
+ Reader reader = ConfigFileHelper.getConfigFileReader(getClass(), "sampleConfig.json");
+ _config = configReader.readConfig(reader);
+ }
+
+ public void testReadTest()
+ {
+ List<TestConfig> tests = _config.getTestConfigs();
+ assertEquals("Unexpected number of tests", 2, tests.size());
+ TestConfig test1Config = tests.get(0);
+ assertNotNull("Test 1 configuration is expected", test1Config);
+ assertEquals("Unexpected test name", "Test 1", test1Config.getName());
+
+ TestConfig test2Config = tests.get(1);
+ assertNotNull("Test 2 configuration is expected", test2Config);
+ }
+
+ public void testReadsTestWithQueues()
+ {
+ TestConfig test1Config = _config.getTestConfigs().get(0);
+ List<QueueConfig> queues = test1Config.getQueues();
+ assertEquals("Unexpected number of queues", 2, queues.size());
+ QueueConfig queue1Config = queues.get(0);
+ assertNotNull("Expected queue 1 config", queue1Config);
+ assertEquals("Unexpected queue name", "Json-Queue-Name", queue1Config.getName());
+ assertTrue("Unexpected attributes", queue1Config.getAttributes().isEmpty());
+ assertFalse("Unexpected durable", queue1Config.isDurable());
+
+ QueueConfig queue2Config = queues.get(1);
+ assertNotNull("Expected queue 2 config", queue2Config);
+ assertEquals("Unexpected queue name", "Json Queue Name 2", queue2Config.getName());
+ assertTrue("Unexpected durable", queue2Config.isDurable());
+ Map<String, Object> attributes = queue2Config.getAttributes();
+ assertNotNull("Expected attributes", attributes);
+ assertFalse("Attributes are not loaded", attributes.isEmpty());
+ assertEquals("Unexpected number of attributes", 1, attributes.size());
+ assertEquals("Unexpected attribute 'x-qpid-priorities' value", 10,
+ ((Number)attributes.get("x-qpid-priorities")).intValue());
+ }
+
+ public void testReadsTestWithIterations()
+ {
+ TestConfig testConfig = _config.getTestConfigs().get(0);
+ List<IterationValue> iterationValues = testConfig.getIterationValues();
+ assertEquals("Unexpected number of iterations", 2, iterationValues.size());
+
+ IterationValue iteration1 = iterationValues.get(0);
+
+ String messageSizeProperty = "_messageSize";
+
+ assertEquals("Unexpected value for property " + messageSizeProperty,
+ "100",
+ iteration1.getIterationPropertyValuesWithUnderscores().get(messageSizeProperty));
+ }
+
+ public void testReadsMessageProviders()
+ {
+ TestConfig testConfig = _config.getTestConfigs().get(0);
+ ClientConfig cleintConfig = testConfig.getClients().get(0);
+ List<MessageProviderConfig> configs = cleintConfig.getMessageProviders();
+ assertNotNull("Message provider configs should not be null", configs);
+ assertEquals("Unexpected number of message providers", 1, configs.size());
+ MessageProviderConfig messageProvider = configs.get(0);
+ assertNotNull("Message provider config should not be null", messageProvider);
+ assertEquals("Unexpected provider name", "testProvider1", messageProvider.getName());
+ Map<String, PropertyValue> properties = messageProvider.getMessageProperties();
+ assertNotNull("Message properties should not be null", properties);
+ assertEquals("Unexpected number of message properties", 3, properties.size());
+ assertNotNull("test property is not found", properties.get("test"));
+ assertNotNull("priority property is not found", properties.get("priority"));
+ assertNotNull("id property is not found", properties.get("id"));
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java
new file mode 100644
index 0000000000..88750b9737
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class ConfigTest extends TestCase
+{
+ public void testGetTestsForTestWithIteratingMessageSizes()
+ {
+ Config config = createConfigWithIteratingMessageSizes();
+ List<TestInstance> testConfigs = config.getTests();
+
+ assertEquals("should have a test config for each message size", 2, testConfigs.size());
+
+ TestInstance instance0 = testConfigs.get(0);
+ assertEquals(0, instance0.getIterationNumber());
+
+ TestInstance instance1 = testConfigs.get(1);
+ assertEquals(1, instance1.getIterationNumber());
+ }
+
+ private Config createConfigWithIteratingMessageSizes()
+ {
+ TestConfig testConfig = mock(TestConfig.class);
+
+ when(testConfig.getIterationValues()).thenReturn(Arrays.asList(new IterationValue(),new IterationValue()));
+
+ Config config = new Config(testConfig);
+
+ return config;
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java
new file mode 100644
index 0000000000..ce5f92724f
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java
@@ -0,0 +1,56 @@
+/*
+ * 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.disttest.controller.config;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.Command;
+
+public class ConfigTestUtils
+{
+ public static <C extends Command> void assertCommandForClient(final List<CommandForClient> commandsForClients, final int index, final String expectedRegisteredClientName, final Class<C> expectedCommandClass)
+ {
+ final CommandForClient commandForClient = commandsForClients.get(index);
+ assertEquals(expectedRegisteredClientName, commandForClient.getClientName());
+ final Command command = commandForClient.getCommand();
+ assertTrue("Command " + index + " is of class " + command.getClass() + " but expecting " + expectedCommandClass,
+ expectedCommandClass.isAssignableFrom(command.getClass()));
+ }
+
+ public static <C extends Command> void assertCommandEquals(final List<Command> commands, final int index, final Class<C> expectedCommandClass)
+ {
+ @SuppressWarnings("unchecked")
+ C command = (C) getCommand(commands, index); //explicit cast added to get round oracle compiler bug (id 6302954)
+ assertTrue("Command " + index + " is of class " + command.getClass() + " but expecting " + expectedCommandClass,
+ expectedCommandClass.isAssignableFrom(command.getClass()));
+ }
+
+ public static <C extends Command> C getCommand(final List<Command> commands, final int index)
+ {
+ @SuppressWarnings("unchecked")
+ C command = (C) commands.get(index);
+ return command;
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java
new file mode 100644
index 0000000000..7c839ed462
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.assertCommandEquals;
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.getCommand;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+
+public class ConnectionConfigTest extends TestCase
+{
+ private static final String CONNECTION_FACTORY_NAME = "ConnectionFactoryName";
+ private static final String CONNECTION_NAME = "ConnectionName";
+
+ public void testConnectionConfigHasZeroArgConstructorForGson()
+ {
+ ConnectionConfig c = new ConnectionConfig();
+ assertNotNull(c);
+ }
+
+ public void testCreateCommandsForConnectionAndChildren()
+ {
+ ConnectionConfig connectionConfig = createConnectionConfigWithChildCommands();
+
+ List<Command> commands = connectionConfig.createCommands();
+ assertEquals(3, commands.size());
+
+ assertCommandEquals(commands, 0, CreateConnectionCommand.class);
+ assertCommandEquals(commands, 1, NoOpCommand.class);
+ assertCommandEquals(commands, 2, NoOpCommand.class);
+
+ CreateConnectionCommand createConnectionCommand = getCommand(commands, 0);
+ assertEquals(CONNECTION_NAME, createConnectionCommand.getConnectionName());
+ assertEquals(CONNECTION_FACTORY_NAME, createConnectionCommand.getConnectionFactoryName());
+ }
+
+ public void testGetTotalNumberOfParticipants()
+ {
+ ConnectionConfig connectionConfig = createConnectionConfigWithTwoParticipants();
+ assertEquals(2, connectionConfig.getTotalNumberOfParticipants());
+ }
+
+ private ConnectionConfig createConnectionConfigWithTwoParticipants()
+ {
+ SessionConfig sessionConfig1 = mock(SessionConfig.class);
+ SessionConfig sessionConfig2 = mock(SessionConfig.class);
+
+ when(sessionConfig1.getTotalNumberOfParticipants()).thenReturn(1);
+ when(sessionConfig2.getTotalNumberOfParticipants()).thenReturn(1);
+
+ ConnectionConfig connectionConfig = new ConnectionConfig(CONNECTION_NAME, CONNECTION_FACTORY_NAME, sessionConfig1, sessionConfig2);
+
+ return connectionConfig;
+ }
+
+ private ConnectionConfig createConnectionConfigWithChildCommands()
+ {
+ SessionConfig sessionConfig = mock(SessionConfig.class);
+
+ NoOpCommand cmd1 = mock(NoOpCommand.class);
+ NoOpCommand cmd2 = mock(NoOpCommand.class);
+ List<Command> commands = Arrays.asList((Command)cmd1, (Command)cmd2);
+ when(sessionConfig.createCommands(CONNECTION_NAME)).thenReturn(commands);
+
+ return new ConnectionConfig(CONNECTION_NAME, CONNECTION_FACTORY_NAME, sessionConfig);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java
new file mode 100644
index 0000000000..c011ff4711
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.disttest.controller.config;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+
+public class ConsumerConfigTest extends TestCase
+{
+ public void testConsumerHasZeroArgConstructorForGson()
+ {
+ ConsumerConfig c = new ConsumerConfig();
+ assertNotNull(c);
+ }
+
+ public void testCreateConsumerCommand()
+ {
+ boolean isTopic = true;
+ boolean isDurableSubscription = true;
+ boolean isBrowsingSubscription = true;
+ boolean noLocal = true;
+ long numberOfMessages = 100;
+ String consumerName = "consumerName";
+ String sessionName = "sessionName";
+ String destinationName = "destinationName";
+ String selector = "selector";
+ int batchSize = 10;;
+ long maximumDuration = 50;
+ boolean isSynchronousNonDefault = false;
+
+ ConsumerConfig consumerConfig = new ConsumerConfig(
+ consumerName,
+ destinationName,
+ numberOfMessages,
+ batchSize,
+ maximumDuration,
+ isTopic,
+ isDurableSubscription,
+ isBrowsingSubscription,
+ selector,
+ noLocal,
+ isSynchronousNonDefault);
+
+ CreateConsumerCommand createConsumerCommand = consumerConfig.createCommand(sessionName);
+
+ assertEquals(sessionName, createConsumerCommand.getSessionName());
+ assertEquals(consumerName, createConsumerCommand.getParticipantName());
+ assertEquals(destinationName, createConsumerCommand.getDestinationName());
+ assertEquals(numberOfMessages, createConsumerCommand.getNumberOfMessages());
+ assertEquals(batchSize, createConsumerCommand.getBatchSize());
+ assertEquals(maximumDuration, createConsumerCommand.getMaximumDuration());
+
+ assertEquals(isTopic, createConsumerCommand.isTopic());
+ assertEquals(isDurableSubscription, createConsumerCommand.isDurableSubscription());
+ assertEquals(isBrowsingSubscription, createConsumerCommand.isBrowsingSubscription());
+ assertEquals(selector, createConsumerCommand.getSelector());
+ assertEquals(noLocal, createConsumerCommand.isNoLocal());
+ assertEquals(isSynchronousNonDefault, createConsumerCommand.isSynchronous());
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java
new file mode 100644
index 0000000000..7998eae37e
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.util.Collections;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+
+public class IterationValueTest extends TestCase
+{
+ private static final int MESSAGE_SIZE = 10;
+
+ private CreateProducerCommand _createProducerCommand;
+ private CreateConsumerCommand _createConsumerCommand;
+ private Map<String, String> _iterationValueMap;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _createProducerCommand = mock(CreateProducerCommand.class);
+ _createConsumerCommand = mock(CreateConsumerCommand.class);
+
+ _iterationValueMap = Collections.singletonMap("_messageSize", String.valueOf(MESSAGE_SIZE));
+ }
+
+ public void testApplyPopulatedIterationValueToCommandWithMatchingProperties() throws Exception
+ {
+ IterationValue iterationValue = new IterationValue(_iterationValueMap);
+
+ iterationValue.applyToCommand(_createProducerCommand);
+
+ verify(_createProducerCommand).setMessageSize(MESSAGE_SIZE);
+ }
+
+ public void testApplyPopulatedIterationValueToCommandWithoutMatchingProperties() throws Exception
+ {
+ IterationValue iterationValue = new IterationValue(_iterationValueMap);
+
+ iterationValue.applyToCommand(_createConsumerCommand);
+
+ verifyZeroInteractions(_createConsumerCommand);
+ }
+
+ public void testApplyUnpopulatedIterationValueToCommand() throws Exception
+ {
+ IterationValue iterationValue = new IterationValue();
+
+ iterationValue.applyToCommand(_createProducerCommand);
+
+ verifyZeroInteractions(_createProducerCommand);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java
new file mode 100644
index 0000000000..a3b367a4b4
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.disttest.controller.config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+
+public class MessageProviderConfigTest extends TestCase
+{
+ public void testCreateCommandsForMessageProvider()
+ {
+ Map<String, PropertyValue> messageProperties = new HashMap<String, PropertyValue>();
+ messageProperties.put("test", new SimplePropertyValue("testValue"));
+ MessageProviderConfig config = new MessageProviderConfig("test", messageProperties);
+ CreateMessageProviderCommand command = config.createCommand();
+ assertNotNull("Command should not be null", command);
+ assertNotNull("Unexpected name", command.getProviderName());
+ assertEquals("Unexpected properties", messageProperties, command.getMessageProperties());
+ }
+
+ public void testMessageProviderConfig()
+ {
+ Map<String, PropertyValue> messageProperties = new HashMap<String, PropertyValue>();
+ messageProperties.put("test", new SimplePropertyValue("testValue"));
+ MessageProviderConfig config = new MessageProviderConfig("test", messageProperties);
+ assertEquals("Unexpected name", "test", config.getName());
+ assertEquals("Unexpected properties", messageProperties, config.getMessageProperties());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java
new file mode 100644
index 0000000000..b9e591f113
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.disttest.controller.config;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+
+public class ProducerConfigTest extends TestCase
+{
+ public void testProducerHasZeroArgConstructorForGson()
+ {
+ ProducerConfig p = new ProducerConfig();
+ assertNotNull(p);
+ }
+
+ public void testConfigProvidesJmsDefaults()
+ {
+ CreateProducerCommand p = new ProducerConfig().createCommand("session1");
+ assertEquals(Message.DEFAULT_DELIVERY_MODE, p.getDeliveryMode());
+ assertEquals(Message.DEFAULT_PRIORITY, p.getPriority());
+ assertEquals(Message.DEFAULT_TIME_TO_LIVE, p.getTimeToLive());
+ }
+
+ public void testCreateProducerCommand()
+ {
+ String destination = "url:/destination";
+ int messageSize = 1000;
+ int numberOfMessages = 10;
+ int priority = 4;
+ long timeToLive = 10000;
+ int batchSize = 5;
+ long interval = 60;
+ long maximumDuration = 70;
+ long startDelay = 80;
+ String providerName = "testProvider1";
+
+ ProducerConfig producerConfig = new ProducerConfig(
+ "producer1",
+ destination,
+ numberOfMessages,
+ batchSize,
+ maximumDuration,
+ DeliveryMode.NON_PERSISTENT,
+ messageSize,
+ priority,
+ timeToLive,
+ interval,
+ startDelay,
+ providerName);
+
+ CreateProducerCommand command = producerConfig.createCommand("session1");
+
+ assertEquals("session1", command.getSessionName());
+ assertEquals("producer1", command.getParticipantName());
+ assertEquals(destination, command.getDestinationName());
+ assertEquals(numberOfMessages, command.getNumberOfMessages());
+ assertEquals(batchSize, command.getBatchSize());
+ assertEquals(maximumDuration, command.getMaximumDuration());
+
+ assertEquals(DeliveryMode.NON_PERSISTENT, command.getDeliveryMode());
+ assertEquals(messageSize, command.getMessageSize());
+ assertEquals(priority, command.getPriority());
+ assertEquals(timeToLive, command.getTimeToLive());
+ assertEquals(interval, command.getInterval());
+ assertEquals(startDelay, command.getStartDelay());
+ assertEquals(providerName, command.getMessageProviderName());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java
new file mode 100644
index 0000000000..8775e4064d
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.assertCommandEquals;
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.getCommand;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.jms.Session;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+
+public class SessionConfigTest extends TestCase
+{
+ private static final String CONNECTION_NAME = "conn1";
+ private static final String SESSION = "session1";
+
+ public void testSessionHasZeroArgConstructorForGson()
+ {
+ SessionConfig s = new SessionConfig();
+ assertNotNull(s);
+ }
+
+ public void testCreateCommandsForSessionAndChildren()
+ {
+ SessionConfig sessionConfig = createSessionConfigWithChildCommands();
+
+ List<Command> commands = sessionConfig.createCommands(CONNECTION_NAME);
+ assertEquals(3, commands.size());
+
+ assertCommandEquals(commands, 0, CreateSessionCommand.class);
+ assertCommandEquals(commands, 1, CreateProducerCommand.class);
+ assertCommandEquals(commands, 2, CreateConsumerCommand.class);
+
+ CreateSessionCommand createSessionCommand = getCommand(commands, 0);
+ assertEquals(Session.AUTO_ACKNOWLEDGE, createSessionCommand.getAcknowledgeMode());
+ assertEquals(SESSION, createSessionCommand.getSessionName());
+ assertEquals(CONNECTION_NAME, createSessionCommand.getConnectionName());
+ }
+
+ public void testGetTotalNumberOfParticipants()
+ {
+ SessionConfig sessionConfig = createSessionConfigWithOneConsumerAndOneProducer();
+ assertEquals(2, sessionConfig.getTotalNumberOfParticipants());
+ }
+
+ private SessionConfig createSessionConfigWithOneConsumerAndOneProducer()
+ {
+ return createSessionConfigWithChildCommands();
+ }
+
+ private SessionConfig createSessionConfigWithChildCommands()
+ {
+ ProducerConfig producerConfig = mock(ProducerConfig.class);
+ ConsumerConfig consumerConfig = mock(ConsumerConfig.class);
+
+ when(producerConfig.createCommand(SESSION)).thenReturn(mock(CreateProducerCommand.class));
+ when(consumerConfig.createCommand(SESSION)).thenReturn(mock(CreateConsumerCommand.class));
+
+ return new SessionConfig(SESSION,
+ Session.AUTO_ACKNOWLEDGE,
+ Collections.singletonList(consumerConfig),
+ Collections.singletonList(producerConfig));
+ }
+
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java
new file mode 100644
index 0000000000..1212a57606
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.apache.qpid.disttest.controller.config.ConfigTestUtils.assertCommandForClient;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.NoOpCommand;
+
+public class TestConfigTest extends TestCase
+{
+ private static final QueueConfig[] EMPTY_QUEUES_ARRAY = new QueueConfig[0];
+ private static final String CLIENT1 = "client1";
+ private static final String CLIENT2 = "client2";
+ private static final String TEST1 = "test1";
+
+ public void testConfigHasZeroArgConstructorForGson()
+ {
+ TestConfig c = new TestConfig();
+ assertNotNull(c);
+ }
+
+ public void testCreateCommandsForClient()
+ {
+ TestConfig config = createTestConfigWithClientConfigReturningChildCommands();
+
+ List<CommandForClient> commandsForClients = config.createCommands();
+ assertEquals("Unexpected number of commands for client", 3, commandsForClients.size());
+
+ assertCommandForClient(commandsForClients, 0, CLIENT1, NoOpCommand.class);
+ assertCommandForClient(commandsForClients, 1, CLIENT1, NoOpCommand.class);
+ assertCommandForClient(commandsForClients, 2, CLIENT2, NoOpCommand.class);
+ }
+
+ public void testGetClientNames()
+ {
+ TestConfig config = createTestConfigWithTwoClients();
+
+ assertEquals(2, config.getClientNames().size());
+ }
+
+ public void testGetTotalNumberOfClients()
+ {
+ TestConfig config = createTestConfigWithTwoClients();
+ assertEquals(2, config.getTotalNumberOfClients());
+ }
+
+ public void testGetTotalNumberOfParticipants()
+ {
+ TestConfig config = createTestConfigWithTwoClients();
+ assertEquals(2, config.getTotalNumberOfParticipants());
+ }
+
+ private TestConfig createTestConfigWithClientConfigReturningChildCommands()
+ {
+ ClientConfig clientConfig1 = createClientConfigReturningCommands(CLIENT1, 2);
+ ClientConfig clientConfig2 = createClientConfigReturningCommands(CLIENT2, 1);
+
+ TestConfig config = new TestConfig(TEST1, new ClientConfig[] { clientConfig1, clientConfig2 }, EMPTY_QUEUES_ARRAY);
+ return config;
+ }
+
+ private ClientConfig createClientConfigReturningCommands(final String clientName, int numberOfCommands)
+ {
+ ClientConfig clientConfig = mock(ClientConfig.class);
+
+ List<CommandForClient> commandList = new ArrayList<CommandForClient>();
+
+ for (int i = 1 ; i <= numberOfCommands; i++)
+ {
+ commandList.add(new CommandForClient(clientName, new NoOpCommand()));
+ }
+
+ when(clientConfig.createCommands()).thenReturn(commandList);
+ return clientConfig;
+ }
+
+ private TestConfig createTestConfigWithTwoClients()
+ {
+ ClientConfig clientConfig1 = mock(ClientConfig.class);
+ ClientConfig clientConfig2 = mock(ClientConfig.class);
+
+ when(clientConfig1.getTotalNumberOfParticipants()).thenReturn(1);
+ when(clientConfig2.getTotalNumberOfParticipants()).thenReturn(1);
+
+ TestConfig config = new TestConfig(TEST1, new ClientConfig[] { clientConfig1, clientConfig2 }, EMPTY_QUEUES_ARRAY);
+ return config;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java
new file mode 100644
index 0000000000..928fbe58cf
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.disttest.controller.config;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.controller.CommandForClient;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+
+public class TestInstanceTest extends TestCase
+{
+ private static final String CLIENT_NAME = "CLIENT_NAME";
+ private static final int ITERATION_NUMBER = 0;
+
+ private NoOpCommand _noOpCommand;
+ private CreateProducerCommand _createProducerCommand;
+ private CreateConsumerCommand _createConsumerCommand;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _noOpCommand = mock(NoOpCommand.class);
+ _createProducerCommand = mock(CreateProducerCommand.class);
+ _createConsumerCommand = mock(CreateConsumerCommand.class);
+ }
+
+ public void testCreateCommandsWithIterationValues()
+ {
+ IterationValue iterationValue = mock(IterationValue.class);
+
+ TestConfig config = createTestConfig();
+
+ TestInstance testInstance = new TestInstance(config, ITERATION_NUMBER, iterationValue);
+
+ List<CommandForClient> commandsForClients = testInstance.createCommands();
+ assertEquals("Unexpected number of commands for client", 3, commandsForClients.size());
+
+ verify(iterationValue).applyToCommand(_noOpCommand);
+ verify(iterationValue).applyToCommand(_createProducerCommand);
+ verify(iterationValue).applyToCommand(_createConsumerCommand);
+ }
+
+ public void testCreateCommandsWithoutIterationValues()
+ {
+ TestConfig config = createTestConfig();
+ TestInstance testInstance = new TestInstance(config);
+
+ List<CommandForClient> commandsForClients = testInstance.createCommands();
+ assertEquals("Unexpected number of commands for client", 3, commandsForClients.size());
+ }
+
+ public void testGetConfiguredClientNames()
+ {
+ TestConfig testConfig = mock(TestConfig.class);
+ when(testConfig.getClientNames()).thenReturn(Collections.singletonList(CLIENT_NAME));
+ TestInstance testInstance = new TestInstance(testConfig);
+
+ List<String> clientNames = testInstance.getClientNames();
+ assertEquals(1, clientNames.size());
+ assertEquals(CLIENT_NAME, clientNames.get(0));
+ }
+
+ private TestConfig createTestConfig()
+ {
+ CommandForClient commandForClient1 = new CommandForClient(CLIENT_NAME, _noOpCommand);
+ CommandForClient commandForClient2 = new CommandForClient(CLIENT_NAME, _createProducerCommand);
+ CommandForClient commandForClient3 = new CommandForClient(CLIENT_NAME, _createConsumerCommand);
+
+ TestConfig config = mock(TestConfig.class);
+ when(config.createCommands()).thenReturn(Arrays.asList(commandForClient1, commandForClient2, commandForClient3));
+
+ return config;
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json
new file mode 100644
index 0000000000..9e1168129b
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json
@@ -0,0 +1,72 @@
+{
+ "_tests": [
+ {
+ "_name": "Test 1",
+ "_queues": [
+ {
+ "_name": "Json-Queue-Name",
+ "_durable": false,
+ "_attributes": {}
+ },
+ {
+ "_name": "Json Queue Name 2",
+ "_durable": true,
+ "_attributes": {
+ "x-qpid-priorities": 10.0
+ }
+ }
+ ],
+ "_iterations": [
+ {
+ "_messageSize": 100,
+ "_numberOfMessages": 10
+ },
+ {
+ "_messageSize": 200,
+ "_numberOfMessages": 5
+ }
+ ],
+ "_clients": [
+ {
+ "_connections": [
+ {
+ "_name": "connection1",
+ "_sessions": []
+ }
+ ];
+ "_messageProviders":[
+ {
+ "_name": "testProvider1";
+ "_messageProperties": {
+ "priority": {"@def": "list"; "_items": [1,2,3,4,4]};
+ "id": {"@def": "random"; "_upper": 10};
+ "test": "test-value"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "Test 2",
+ "_queues": [
+ {
+ "_name": "Json-Queue-Name",
+ "_durable": false,
+ "_attributes": {}
+ }
+ ],
+ "_iterations": [],
+ "_clients": [
+ {
+ "_connections": [
+ {
+ "_name": "connection1",
+ "_sessions": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java
new file mode 100644
index 0000000000..ab0f52263b
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.disttest.jms;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+
+public class JmsMessageAdaptorTest extends TestCase
+{
+
+ public void testCheckAllCommandTypes()
+ {
+ for (CommandType commandType : CommandType.values())
+ {
+ Class<? extends Command> clazz = JmsMessageAdaptor.getCommandClassFromType(commandType);
+ assertNotNull(clazz);
+
+ }
+
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java
new file mode 100644
index 0000000000..4a56fff8fe
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.disttest.message;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.qpid.disttest.client.property.ListPropertyValue;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.json.JsonHandler;
+
+public class JsonHandlerTest extends TestCase
+{
+ private JsonHandler _jsonHandler = null;
+ private SendChristmasCards _testCommand = null;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _jsonHandler = new JsonHandler();
+
+ _testCommand = new SendChristmasCards(CommandType.START_TEST, Collections.singletonMap(SendChristmasCards.CardType.FUNNY, 5));
+ _testCommand.persons = Arrays.asList(new Person("Phil"), new Person("Andrew"));
+ }
+
+ public void testMarshallUnmarshall() throws Exception
+ {
+ final String jsonString = _jsonHandler.marshall(_testCommand);
+
+ final SendChristmasCards unmarshalledCommand = _jsonHandler.unmarshall(jsonString, SendChristmasCards.class);
+
+ assertEquals("Unmarshalled command should be equal to the original object", _testCommand, unmarshalledCommand);
+ }
+
+ public void testGeneratorDesrialization()
+ {
+ String json = "{_messageProperties: {test: 1; generator: {'@def': 'list'; _cyclic: false; _items: ['first', " +
+ "{'@def': 'range'; _upper:10; '_type':'int'}]}}}";
+ final TestCommand unmarshalledCommand = _jsonHandler.unmarshall(json, TestCommand.class);
+ Map<String, PropertyValue> properties = unmarshalledCommand.getMessageProperties();
+ assertNotNull("Properties should not be null", properties);
+ assertFalse("Properties should not be empty", properties.isEmpty());
+ assertEquals("Unexpected properties size", 2, properties.size());
+ PropertyValue testProperty = properties.get("test");
+ assertNotNull("Unexpected property test", testProperty);
+ assertTrue("Unexpected property test", testProperty.getValue() instanceof Number);
+ assertEquals("Unexpected property value", 1, ((Number)testProperty.getValue()).intValue());
+ Object generatorObject = properties.get("generator");
+ assertTrue("Unexpected generator object", generatorObject instanceof ListPropertyValue);
+ PropertyValue generator = (PropertyValue)generatorObject;
+ assertEquals("Unexpected generator value", "first", generator.getValue());
+ for (int i = 0; i < 10; i++)
+ {
+ assertEquals("Unexpected generator value", new Integer(i), generator.getValue());
+ }
+ String newJson =_jsonHandler.marshall(unmarshalledCommand);
+ final TestCommand newUnmarshalledCommand = _jsonHandler.unmarshall(newJson, TestCommand.class);
+ assertEquals("Unmarshalled command should be equal to the original object", unmarshalledCommand, newUnmarshalledCommand);
+ }
+
+ /**
+ * A {@link Command} designed to exercise {@link JsonHandler}, e.g does it handle a map of enums?.
+ *
+ * This class is non-private to avoid auto-deletion of "unused" fields/methods
+ */
+ static class SendChristmasCards extends Command
+ {
+ enum CardType {FUNNY, TRADITIONAL}
+
+ private Map<CardType, Integer> _cardTypes;
+ private List<Person> persons;
+
+ public SendChristmasCards(final CommandType type, Map<CardType, Integer> cardTypes)
+ {
+ super(type);
+ _cardTypes = cardTypes;
+ }
+
+ public Map<CardType, Integer> getCardTypes()
+ {
+ return _cardTypes;
+ }
+
+ public List<Person> getPersons()
+ {
+ return persons;
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+ }
+
+ /**
+ * This class is non-private to avoid auto-deletion of "unused" fields/methods
+ */
+ static class Person
+ {
+ private String _firstName;
+
+ public Person(final String firstName)
+ {
+ _firstName = firstName;
+ }
+
+ public String getFirstName()
+ {
+ return _firstName;
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ }
+
+ /**
+ * Yet another test class
+ */
+ static class TestCommand extends Command
+ {
+
+ private Map<String, PropertyValue> _messageProperties;
+
+ public TestCommand(CommandType type)
+ {
+ super(type);
+ }
+
+ public Map<String, PropertyValue> getMessageProperties()
+ {
+ return _messageProperties;
+ }
+
+ public void setMessageProperties(Map<String, PropertyValue> _messageProperties)
+ {
+ this._messageProperties = _messageProperties;
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj == null || !(obj instanceof TestCommand))
+ {
+ return false;
+ }
+ TestCommand other = (TestCommand)obj;
+ if (_messageProperties == null && other._messageProperties != null )
+ {
+ return false;
+ }
+ return _messageProperties.equals(other._messageProperties);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java
new file mode 100644
index 0000000000..ee095ce199
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.disttest.message;
+
+import static org.apache.qpid.disttest.message.ParticipantAttribute.BATCH_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.CONFIGURED_CLIENT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.DELIVERY_MODE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.ERROR_MESSAGE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_BROWSIING_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_DURABLE_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_NO_LOCAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SELECTOR;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SYNCHRONOUS_CONSUMER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_TOPIC;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.ITERATION_NUMBER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.MAXIMUM_DURATION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PAYLOAD_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.NUMBER_OF_MESSAGES_PROCESSED;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PARTICIPANT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRIORITY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_INTERVAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_START_DELAY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TEST_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TIME_TAKEN;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TIME_TO_LIVE;
+
+import java.util.Date;
+
+import javax.jms.DeliveryMode;
+
+import junit.framework.TestCase;
+
+public class ParticipantResultTest extends TestCase
+{
+
+ public void testSharedParticipantResultAttributes() throws Exception
+ {
+ final String participantName = "PARTICIPANT_NAME1";
+ final String testName = "TEST_NAME1";
+ String clientConfiguredName = "CLIENT_CONFIGURED_NAME";
+ String errorMessage = "errorMessage";
+ int iterationNumber = 1;
+
+ ParticipantResult result = new ParticipantResult();
+
+ long numberOfMessages = 500;
+ long timeTaken = 30;
+ int batchSize = 10;
+
+ long startTime = System.currentTimeMillis();
+ long endTime = startTime + timeTaken;
+ long maximumDuration = 1000;
+
+ result.setParticipantName(participantName);
+ result.setTestName(testName);
+ result.setIterationNumber(iterationNumber);
+ result.setConfiguredClientName(clientConfiguredName);
+
+ result.setNumberOfMessagesProcessed(numberOfMessages);
+ result.setConfiguredClientName(clientConfiguredName);
+ result.setBatchSize(10);
+
+ result.setStartDate(new Date(startTime));
+ result.setEndDate(new Date(endTime));
+ result.setMaximumDuration(maximumDuration);
+
+ result.setErrorMessage(errorMessage);
+
+ assertEquals(participantName, result.getAttributes().get(PARTICIPANT_NAME));
+ assertEquals(testName, result.getAttributes().get(TEST_NAME));
+ assertEquals(clientConfiguredName, result.getAttributes().get(CONFIGURED_CLIENT_NAME));
+ assertEquals(numberOfMessages, result.getAttributes().get(NUMBER_OF_MESSAGES_PROCESSED));
+ assertEquals(timeTaken, result.getAttributes().get(TIME_TAKEN));
+ assertEquals(batchSize, result.getAttributes().get(BATCH_SIZE));
+ assertEquals(maximumDuration, result.getAttributes().get(MAXIMUM_DURATION));
+ assertEquals(errorMessage, result.getAttributes().get(ERROR_MESSAGE));
+ assertEquals(iterationNumber, result.getAttributes().get(ITERATION_NUMBER));
+ }
+
+ public void testConsumerParticipantResultAttributes() throws Exception
+ {
+ ConsumerParticipantResult result = new ConsumerParticipantResult();
+
+ boolean topic = true;
+ boolean durable = true;
+ boolean browsingSubscription = false;
+ boolean selector = true;
+ boolean noLocal = false;
+ boolean synchronousConsumer = true;
+
+ result.setTopic(topic);
+ result.setDurableSubscription(durable);
+ result.setBrowsingSubscription(browsingSubscription);
+ result.setSelector(selector);
+ result.setNoLocal(noLocal);
+ result.setSynchronousConsumer(synchronousConsumer);
+
+ assertEquals(topic, result.getAttributes().get(IS_TOPIC));
+ assertEquals(durable, result.getAttributes().get(IS_DURABLE_SUBSCRIPTION));
+ assertEquals(browsingSubscription, result.getAttributes().get(IS_BROWSIING_SUBSCRIPTION));
+ assertEquals(selector, result.getAttributes().get(IS_SELECTOR));
+ assertEquals(noLocal, result.getAttributes().get(IS_NO_LOCAL));
+ assertEquals(synchronousConsumer, result.getAttributes().get(IS_SYNCHRONOUS_CONSUMER));
+ }
+
+ public void testProducerParticipantResultAttributes() throws Exception
+ {
+ ProducerParticipantResult result = new ProducerParticipantResult();
+
+ int priority = 2;
+ long timeToLive = 30;
+ long producerStartDelay = 40;
+ long producerInterval = 50;
+ int messageSize = 60;
+ int deliveryMode = DeliveryMode.PERSISTENT;
+
+ result.setPriority(priority);
+ result.setTimeToLive(timeToLive);
+ result.setStartDelay(producerStartDelay);
+ result.setInterval(producerInterval);
+ result.setPayloadSize(messageSize);
+ result.setDeliveryMode(deliveryMode);
+
+
+ assertEquals(priority, result.getAttributes().get(PRIORITY));
+ assertEquals(timeToLive, result.getAttributes().get(TIME_TO_LIVE));
+ assertEquals(producerStartDelay, result.getAttributes().get(PRODUCER_START_DELAY));
+ assertEquals(producerInterval, result.getAttributes().get(PRODUCER_INTERVAL));
+ assertEquals(messageSize, result.getAttributes().get(PAYLOAD_SIZE));
+ assertEquals(deliveryMode, result.getAttributes().get(DELIVERY_MODE));
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java
new file mode 100644
index 0000000000..393837b4d5
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+
+public class AggregatorTest extends TestCase
+{
+ private Aggregator _aggregator = new Aggregator();
+ private TestResultAggregator _testResultAggregator = mock(TestResultAggregator.class);
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _aggregator.setTestResultAggregator(_testResultAggregator);
+ }
+
+ public void testAggregrateManyTestResults() throws Exception
+ {
+ ResultsForAllTests resultsForAllTests = mock(ResultsForAllTests.class);
+ ITestResult testResult1 = mock(ITestResult.class);
+ ITestResult testResult2 = mock(ITestResult.class);
+
+ when(resultsForAllTests.getTestResults()).thenReturn(Arrays.asList(testResult1, testResult2));
+ when(_testResultAggregator.aggregateTestResult(testResult1)).thenReturn(mock(AggregatedTestResult.class));
+ when(_testResultAggregator.aggregateTestResult(testResult2)).thenReturn(mock(AggregatedTestResult.class));
+
+ ResultsForAllTests aggregatedResultsForAllTests = _aggregator.aggregateResults(resultsForAllTests);
+ assertEquals(2, aggregatedResultsForAllTests.getTestResults().size());
+
+ verify(_testResultAggregator).aggregateTestResult(testResult1);
+ verify(_testResultAggregator).aggregateTestResult(testResult2);
+
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java
new file mode 100644
index 0000000000..5cf84c77f1
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import java.util.Date;
+
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.ParticipantResultAggregator;
+
+import junit.framework.TestCase;
+
+public class ParticipantResultAggregatorTest extends TestCase
+{
+ private ParticipantResultAggregator _aggregator = new ParticipantResultAggregator(ParticipantResult.class, AGGREGATED_RESULT_NAME);
+
+ private static final String TEST_NAME = "TEST_NAME";
+ private static final String AGGREGATED_RESULT_NAME = "AGGREGATED_RESULT_NAME";
+ private static final int TEST_ITERATION_NUMBER = 1;
+
+ private static final long PARTICIPANT1_STARTDATE = 50;
+ private static final long PARTICIPANT1_ENDDATE = 20000;
+ private static final long PARTICIPANT1_TOTAL_PROCESSED = 1024;
+
+ private static final long PARTICIPANT2_STARTDATE = 100;
+ private static final long PARTICIPANT2_ENDDATE = 21000;
+ private static final long PARTICIPANT2_TOTAL_PROCESSED = 2048;
+
+ private static final long OVERALL_PROCESSED = PARTICIPANT1_TOTAL_PROCESSED + PARTICIPANT2_TOTAL_PROCESSED;
+ private static final double OVERALL_TIMETAKEN = PARTICIPANT2_ENDDATE - PARTICIPANT1_STARTDATE;
+
+ private static final double EXPECTED_AGGREGATED_ALL_THROUGHPUT = ((OVERALL_PROCESSED)/1024)/((OVERALL_TIMETAKEN)/1000);
+
+ public void testStartAndEndDateForOneParticipantResult()
+ {
+ ParticipantResult result = new ParticipantResult();
+ result.setStartDate(new Date(PARTICIPANT1_STARTDATE));
+ result.setEndDate(new Date(PARTICIPANT1_ENDDATE));
+
+ _aggregator.aggregate(result);
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(PARTICIPANT1_STARTDATE, aggregratedResult.getStartInMillis());
+ assertEquals(PARTICIPANT1_ENDDATE, aggregratedResult.getEndInMillis());
+ }
+
+ public void testStartAndEndDateForTwoParticipantResults()
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setStartDate(new Date(PARTICIPANT1_STARTDATE));
+ result1.setEndDate(new Date(PARTICIPANT1_ENDDATE));
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setStartDate(new Date(PARTICIPANT2_STARTDATE));
+ result2.setEndDate(new Date(PARTICIPANT2_ENDDATE));
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(PARTICIPANT1_STARTDATE, aggregratedResult.getStartInMillis());
+ assertEquals(PARTICIPANT2_ENDDATE, aggregratedResult.getEndInMillis());
+ }
+
+ public void testComputeNumberOfMessagesProcessed()
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setNumberOfMessagesProcessed(10);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setNumberOfMessagesProcessed(15);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(25, aggregratedResult.getNumberOfMessagesProcessed());
+ }
+
+ public void testComputeTotalPayloadProcessed()
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setTotalPayloadProcessed(PARTICIPANT1_TOTAL_PROCESSED);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setTotalPayloadProcessed(PARTICIPANT2_TOTAL_PROCESSED);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(OVERALL_PROCESSED, aggregratedResult.getTotalPayloadProcessed());
+ }
+
+ public void testComputeThroughput()
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setStartDate(new Date(PARTICIPANT1_STARTDATE));
+ result1.setEndDate(new Date(PARTICIPANT1_ENDDATE));
+ result1.setTotalPayloadProcessed(PARTICIPANT1_TOTAL_PROCESSED);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setStartDate(new Date(PARTICIPANT2_STARTDATE));
+ result2.setEndDate(new Date(PARTICIPANT2_ENDDATE));
+ result2.setTotalPayloadProcessed(PARTICIPANT2_TOTAL_PROCESSED);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(EXPECTED_AGGREGATED_ALL_THROUGHPUT, aggregratedResult.getThroughput(), 0.1);
+ }
+
+ public void testConstantTestNameAndIterationNumberRolledUp() throws Exception
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setTestName(TEST_NAME);
+ result1.setIterationNumber(TEST_ITERATION_NUMBER);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setTestName(TEST_NAME);
+ result2.setIterationNumber(TEST_ITERATION_NUMBER);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(TEST_ITERATION_NUMBER, aggregratedResult.getIterationNumber());
+ assertEquals(TEST_NAME, aggregratedResult.getTestName());
+ }
+
+ public void testConstantPayloadSizesRolledUp() throws Exception
+ {
+ final int payloadSize = 1024;
+
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setPayloadSize(payloadSize);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setPayloadSize(payloadSize);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(payloadSize, aggregratedResult.getPayloadSize());
+ }
+
+ public void testDifferingPayloadSizesNotRolledUp() throws Exception
+ {
+ final int payload1Size = 1024;
+ final int payload2Size = 2048;
+
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setPayloadSize(payload1Size);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setPayloadSize(payload2Size);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(0, aggregratedResult.getPayloadSize());
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java
new file mode 100644
index 0000000000..7cf900ca79
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.disttest.results.aggregation;
+
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.controller.TestResult;
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.AggregatedTestResult;
+import org.apache.qpid.disttest.results.aggregation.TestResultAggregator;
+
+public class TestResultAggregatorTest extends TestCase
+{
+
+ private static final String TEST1_NAME = "TEST1_NAME";
+ private static final int TEST1_ITERATION_NUMBER = 1;
+
+
+ private static final String CONSUMER_PARTICIPANT_NAME1 = "CONSUMER_PARTICIPANT_NAME1";
+ private static final String CONSUMER_PARTICIPANT_NAME2 = "CONSUMER_PARTICIPANT_NAME2";
+
+ private static final String PRODUCER_PARTICIPANT_NAME = "PRODUCER_PARTICIPANT_NAME";
+
+
+ private static final long CONSUMER1_STARTDATE = 50;
+ private static final long CONSUMER1_ENDDATE = 20000;
+
+ private static final long CONSUMER2_STARTDATE = 100;
+ private static final long CONSUMER2_ENDDATE = 21000;
+
+ private static final long PRODUCER_STARTDATE = 0;
+ private static final long PRODUCER_ENDDATE = 19000;
+
+ private static final long NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER = 50;
+ private static final long NUMBER_OF_MESSAGES_CONSUMED_IN_TOTAL = NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER * 2;
+ private static final long NUMBER_OF_MESSAGES_PRODUCED = NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER * 2;
+
+ private static final int PAYLOAD_SIZE = 1024;
+ private static final long TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER = NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER * PAYLOAD_SIZE;
+ private static final long TOTAL_PAYLOAD_PRODUCED_IN_TOTAL = TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER * 2;
+
+ private static final int EXPECTED_NUMBER_OF_AGGREGATED_RESULTS = 3;
+
+ private TestResultAggregator _aggregator = new TestResultAggregator();
+
+ public void testAggregateResultsForTwoConsumerAndOneProducer() throws Exception
+ {
+ TestResult originalTestResult = createResultsFromTest();
+
+ int numberOfOriginalParticipantResults = originalTestResult.getParticipantResults().size();
+ int expectedNumberOfResults = numberOfOriginalParticipantResults + EXPECTED_NUMBER_OF_AGGREGATED_RESULTS;
+
+ AggregatedTestResult aggregatedTestResult = _aggregator.aggregateTestResult(originalTestResult);
+
+ aggregatedTestResult.getAllConsumerParticipantResult().getTotalPayloadProcessed();
+ assertEquals(expectedNumberOfResults, aggregatedTestResult.getParticipantResults().size());
+
+ assertMinimalAggregatedResults(
+ aggregatedTestResult.getAllParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ NUMBER_OF_MESSAGES_CONSUMED_IN_TOTAL);
+
+ assertMinimalAggregatedResults(
+ aggregatedTestResult.getAllConsumerParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ NUMBER_OF_MESSAGES_CONSUMED_IN_TOTAL);
+
+ assertMinimalAggregatedResults(
+ aggregatedTestResult.getAllProducerParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ NUMBER_OF_MESSAGES_PRODUCED);
+ }
+
+ public void testAggregateResultsWhenParticipantErrored()
+ {
+ ParticipantResult failedParticipantResult = new ParticipantResult();
+ failedParticipantResult.setParticipantName(PRODUCER_PARTICIPANT_NAME);
+ failedParticipantResult.setErrorMessage("error");
+ TestResult result = new TestResult(TEST1_NAME);
+ result.addParticipantResult(failedParticipantResult);
+
+ AggregatedTestResult aggregatedTestResult = _aggregator.aggregateTestResult(result);
+ assertEquals(TestResultAggregator.AGGREGATED_ERROR_MESSAGE, aggregatedTestResult.getAllParticipantResult().getErrorMessage());
+ }
+
+ private void assertMinimalAggregatedResults(ParticipantResult result, String expectedTestName, int expectedIterationNumber, long expectedNumberOfMessagesProcessed)
+ {
+ assertEquals("Unexpected test name in " + result.getParticipantName(), expectedTestName, result.getTestName());
+ assertEquals("Unexpected iteration number in " + result.getParticipantName(), expectedIterationNumber, result.getIterationNumber());
+ assertEquals("Unexpected number of messages processed in " + result.getParticipantName(), expectedNumberOfMessagesProcessed, result.getNumberOfMessagesProcessed());
+ }
+
+ private TestResult createResultsFromTest()
+ {
+ TestResult testResult = new TestResult(TEST1_NAME);
+
+ ConsumerParticipantResult consumerResult1 = new ConsumerParticipantResult();
+ setPropertiesOn(consumerResult1, TEST1_NAME, TEST1_ITERATION_NUMBER, CONSUMER_PARTICIPANT_NAME1, NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER, PAYLOAD_SIZE, TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER, CONSUMER1_STARTDATE, CONSUMER1_ENDDATE);
+ testResult.addParticipantResult(consumerResult1);
+
+ ConsumerParticipantResult consumerResult2 = new ConsumerParticipantResult();
+ setPropertiesOn(consumerResult2, TEST1_NAME, TEST1_ITERATION_NUMBER, CONSUMER_PARTICIPANT_NAME2, NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER, PAYLOAD_SIZE, TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER, CONSUMER2_STARTDATE, CONSUMER2_ENDDATE);
+ testResult.addParticipantResult(consumerResult2);
+
+ ParticipantResult producerResult = new ProducerParticipantResult();
+ setPropertiesOn(producerResult, TEST1_NAME, TEST1_ITERATION_NUMBER, PRODUCER_PARTICIPANT_NAME, NUMBER_OF_MESSAGES_PRODUCED, PAYLOAD_SIZE, TOTAL_PAYLOAD_PRODUCED_IN_TOTAL, PRODUCER_STARTDATE, PRODUCER_ENDDATE);
+ testResult.addParticipantResult(producerResult);
+
+ return testResult;
+ }
+
+ private void setPropertiesOn(ParticipantResult participantResult, String testName, int iterationNumber, String participantName, long numberOfMessagesProcessed, int payloadSize, long totalPayloadProcessed, long start, long end)
+ {
+ participantResult.setParticipantName(participantName);
+ participantResult.setTestName(testName);
+ participantResult.setIterationNumber(iterationNumber);
+
+ participantResult.setNumberOfMessagesProcessed(numberOfMessagesProcessed);
+ participantResult.setPayloadSize(payloadSize);
+ participantResult.setTotalPayloadProcessed(totalPayloadProcessed);
+ participantResult.setStartDate(new Date(start));
+ participantResult.setEndDate(new Date(end));
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java
new file mode 100644
index 0000000000..c8f5b3a231
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.disttest.results.formatting;
+
+import static org.apache.qpid.disttest.message.ParticipantAttribute.BATCH_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.CONFIGURED_CLIENT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.DELIVERY_MODE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.ERROR_MESSAGE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_BROWSIING_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_DURABLE_SUBSCRIPTION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_NO_LOCAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SELECTOR;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_SYNCHRONOUS_CONSUMER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.IS_TOPIC;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.ITERATION_NUMBER;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.MAXIMUM_DURATION;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PAYLOAD_SIZE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.NUMBER_OF_MESSAGES_PROCESSED;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PARTICIPANT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRIORITY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_INTERVAL;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PRODUCER_START_DELAY;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TEST_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TIME_TAKEN;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TIME_TO_LIVE;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.THROUGHPUT;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TOTAL_PAYLOAD_PROCESSED;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+import org.apache.qpid.disttest.controller.TestResult;
+import org.apache.qpid.disttest.message.ParticipantAttribute;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.results.formatting.CSVFormater;
+
+public class CSVFormaterTest extends TestCase
+{
+ private static final String TEST1 = "TEST1";
+ private static final String PARTICIPANT = "PARTICIPANT";
+ private static final String CONFIGURED_CLIENT1 = "CONFIGURED_CLIENT1";
+
+ private CSVFormater _formatter = new CSVFormater();
+
+ public void testResultsFileWithWithOneRow() throws Exception
+ {
+ ParticipantResult participantResult = mock(ParticipantResult.class);
+ Map<ParticipantAttribute, Object> participantAttributes = getParticipantAttributes();
+
+ when(participantResult.getAttributes()).thenReturn(participantAttributes);
+
+ TestResult testResult = new TestResult(TEST1);
+ testResult.addParticipantResult(participantResult);
+
+ ResultsForAllTests resultsForAllTests = new ResultsForAllTests();
+ resultsForAllTests.add(testResult);
+
+ String output = _formatter.format(resultsForAllTests);
+
+ String expectedOutput = readCsvOutputFileAsString("expectedOutput.csv");
+
+ assertEquals(expectedOutput, output);
+ }
+
+ private Map<ParticipantAttribute, Object> getParticipantAttributes()
+ {
+ Map<ParticipantAttribute, Object> participantAttributes = new HashMap<ParticipantAttribute, Object>();
+
+ participantAttributes.put(TEST_NAME, TEST1);
+ participantAttributes.put(ITERATION_NUMBER, 0);
+ participantAttributes.put(CONFIGURED_CLIENT_NAME, CONFIGURED_CLIENT1);
+ participantAttributes.put(PARTICIPANT_NAME, PARTICIPANT);
+ participantAttributes.put(NUMBER_OF_MESSAGES_PROCESSED, 1);
+ participantAttributes.put(PAYLOAD_SIZE, 2);
+ participantAttributes.put(PRIORITY, 3);
+ participantAttributes.put(TIME_TO_LIVE, 4);
+ participantAttributes.put(DELIVERY_MODE, 5);
+ participantAttributes.put(BATCH_SIZE, 6);
+ participantAttributes.put(MAXIMUM_DURATION, 7);
+ participantAttributes.put(PRODUCER_START_DELAY, 8);
+ participantAttributes.put(PRODUCER_INTERVAL, 9);
+ participantAttributes.put(IS_TOPIC, true);
+ participantAttributes.put(IS_DURABLE_SUBSCRIPTION, false);
+ participantAttributes.put(IS_BROWSIING_SUBSCRIPTION, true);
+ participantAttributes.put(IS_SELECTOR, false);
+ participantAttributes.put(IS_NO_LOCAL, true);
+ participantAttributes.put(IS_SYNCHRONOUS_CONSUMER, false);
+ participantAttributes.put(TOTAL_PAYLOAD_PROCESSED, 1024);
+ participantAttributes.put(THROUGHPUT, 2048);
+ participantAttributes.put(TIME_TAKEN, 1000);
+ participantAttributes.put(ERROR_MESSAGE, "error");
+
+ return participantAttributes;
+ }
+
+ private String readCsvOutputFileAsString(String filename) throws Exception
+ {
+ InputStream is = getClass().getResourceAsStream(filename);
+ assertNotNull(is);
+
+ StringBuilder output = new StringBuilder();
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ while((line = br.readLine()) != null)
+ {
+ output.append(line);
+ output.append("\n");
+ }
+
+ return output.toString();
+ }
+
+
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java
new file mode 100644
index 0000000000..6cec4b5245
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.disttest.results.formatting;
+
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.TestResultAggregator;
+import org.apache.qpid.disttest.results.formatting.CSVOrderParticipantResultComparator;
+
+public class CSVOrderParticipantResultComparatorTest extends TestCase
+{
+ CSVOrderParticipantResultComparator _comparator = new CSVOrderParticipantResultComparator();
+
+ public void testOrderedConsumerParticipants() throws Exception
+ {
+ assertCompare(
+ new ConsumerParticipantResult("apple"),
+ new ConsumerParticipantResult("banana"));
+
+ }
+ public void testProducerPrecedesConsumerParticipants() throws Exception
+ {
+ assertCompare(
+ new ProducerParticipantResult(),
+ new ConsumerParticipantResult());
+ }
+
+ public void testProducerPrecedesAllProducersResult()
+ {
+ assertCompare(
+ new ProducerParticipantResult("participantName"),
+ new ParticipantResult(TestResultAggregator.ALL_PRODUCER_PARTICIPANTS_NAME));
+ }
+
+ public void testConsumerPrecedesAllConsumersResult()
+ {
+ assertCompare(
+ new ConsumerParticipantResult("participantName"),
+ new ParticipantResult(TestResultAggregator.ALL_CONSUMER_PARTICIPANTS_NAME));
+ }
+
+ public void testAllParticipantsPrecedesAllConsumersResult()
+ {
+ assertCompare(
+ new ParticipantResult(TestResultAggregator.ALL_PARTICIPANTS_NAME),
+ new ParticipantResult(TestResultAggregator.ALL_CONSUMER_PARTICIPANTS_NAME));
+ }
+
+ public void testAllParticipantsPrecedesAllProducersResult()
+ {
+ assertCompare(
+ new ParticipantResult(TestResultAggregator.ALL_PARTICIPANTS_NAME),
+ new ParticipantResult(TestResultAggregator.ALL_PRODUCER_PARTICIPANTS_NAME));
+ }
+
+ private void assertCompare(ParticipantResult smaller, ParticipantResult bigger)
+ {
+ assertEquals("Expected " + smaller + " to 'equal' itself",
+ 0,
+ _comparator.compare(smaller, smaller));
+
+ String failureMsg = "Expected " + smaller + " to be smaller than " + bigger;
+
+ assertTrue(failureMsg, _comparator.compare(smaller, bigger) < 0);
+ assertTrue(failureMsg, _comparator.compare(bigger, smaller) > 0);
+ }
+
+}
+// <ParticipantResult>
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv
new file mode 100644
index 0000000000..08cb2275b5
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv
@@ -0,0 +1,2 @@
+Test Name,Iteration number,Client Name,Participant name,Number of messages,Payload size (bytes),Priority,Time to live (ms),Delivery mode,Batch size,Maximum duration (ms),Producer start delay (ms),Producer interval (ms),Is topic,Is durable subscription,Is browsing subscription,Is selector,Is no local,Is synchronous consumer,Total payload processed (bytes),Throughput (kbytes/s),Time taken (ms),Error message
+TEST1,0,CONFIGURED_CLIENT1,PARTICIPANT,1,2,3,4,5,6,7,8,9,true,false,true,false,true,false,1024,2048,1000,error \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java
new file mode 100644
index 0000000000..96daf64526
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java
@@ -0,0 +1,72 @@
+/*
+ * 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.systest.disttest;
+
+import java.util.Properties;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class DistributedTestSystemTestBase extends QpidBrokerTestCase
+{
+ protected Context _context;
+
+ protected Connection _connection;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ final Properties properties = new Properties();
+ properties.load(DistributedTestSystemTestBase.class.getResourceAsStream("perftests.systests.properties"));
+ _context = new InitialContext(properties);
+
+ _connection = getConnection();
+ _connection.start();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ // no need to close connections - this is done by superclass
+
+ super.tearDown();
+ }
+
+ public Context getContext()
+ {
+ return _context;
+ }
+
+ @Override
+ public Connection getConnection() throws JMSException, NamingException
+ {
+ final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory");
+ final Connection connection = connectionFactory.createConnection();
+ _connections.add(connection);
+ return connection;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java
new file mode 100644
index 0000000000..3fa2b9836e
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.systest.disttest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.disttest.DistributedTestException;
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+import org.apache.qpid.disttest.jms.QpidQueueCreator;
+
+public class QpidQueueCreatorTest extends DistributedTestSystemTestBase
+{
+ private static final Map<String, Object> EMPTY_ATTRIBUTES = Collections.emptyMap();
+
+ private QpidQueueCreator _creator;
+ private Connection _connection;
+ private Session _session;
+ private List<QueueConfig> _configs;
+ private String _queueName;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _creator = new QpidQueueCreator();
+ _configs = new ArrayList<QueueConfig>();
+ _queueName = "direct://amq.direct//" + getTestQueueName();
+ }
+
+ public void testCreateQueueWithoutAttributes() throws Exception
+ {
+ _configs.add(new QueueConfig(_queueName, true, EMPTY_ATTRIBUTES));
+
+ assertQueueBound(_queueName, false);
+
+ _creator.createQueues(_connection, _configs);
+
+ assertQueueBound(_queueName, true);
+ }
+
+ public void testCreateWithAttributes() throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put("x-qpid-priorities", Integer.valueOf(5));
+ _configs.add(new QueueConfig(_queueName, true, attributes));
+
+ assertQueueBound(_queueName, false);
+
+ _creator.createQueues(_connection, _configs);
+
+ assertQueueBound(_queueName, true);
+ }
+
+ public void testDeleteQueues() throws Exception
+ {
+ _configs.add(new QueueConfig(_queueName, true, EMPTY_ATTRIBUTES));
+
+ assertQueueBound(_queueName, false);
+
+ _creator.createQueues(_connection, _configs);
+ assertQueueBound(_queueName, true);
+
+ _creator.deleteQueues(_connection, _configs);
+ assertQueueBound(_queueName, false);
+ }
+
+ public void testDeleteQueueThatDoesNotExist() throws Exception
+ {
+ String queueThatDoesNotExist = _queueName;
+ List<QueueConfig> configs = new ArrayList<QueueConfig>();
+ Map<String, Object> attributes = Collections.emptyMap();
+ configs.add(new QueueConfig(queueThatDoesNotExist, true, attributes));
+
+ try
+ {
+ _creator.deleteQueues(_connection, configs);
+ fail("Exception not thrown");
+ }
+ catch (DistributedTestException e)
+ {
+ // PASS
+ }
+ }
+
+ private void assertQueueBound(String queueName, boolean isBound) throws Exception
+ {
+ AMQDestination destination = (AMQDestination)_session.createQueue(queueName);
+ assertEquals("Queue is not in expected bound state", isBound, ((AMQSession<?, ?>)_session).isQueueBound(destination));
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java
new file mode 100644
index 0000000000..808b428bc9
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java
@@ -0,0 +1,28 @@
+/*
+ * 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.systest.disttest;
+
+public abstract class SystemTestConstants
+{
+ public static final long REGISTRATION_TIMEOUT = 5000;
+ public static final long COMMAND_RESPONSE_TIMEOUT = 10000;
+ public static final long TEST_RESULT_TIMEOUT = 5000;
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java
new file mode 100644
index 0000000000..d599bdc5c4
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.systest.disttest.clientonly;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.ClientState;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.jms.JmsMessageAdaptor;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.NoOpCommand;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StopClientCommand;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+
+public class BasicDistributedClientTest extends DistributedTestSystemTestBase
+{
+ private Session _session = null;
+ private MessageProducer _clientQueueProducer;
+ private Client _client;
+ private ControllerQueue _controllerQueue;
+ private ClientJmsDelegate _clientJmsDelegate = null;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _controllerQueue = new ControllerQueue(_connection, _context);
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _clientJmsDelegate = new ClientJmsDelegate(_context);
+ _client = new Client(_clientJmsDelegate);
+ _client.start();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ _controllerQueue.close();
+ if (_session != null)
+ {
+ _session.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testClientSendsRegistrationMessage() throws Exception
+ {
+ final RegisterClientCommand regClientCommand = _controllerQueue.getNext();
+
+ assertNotNull("Client must have a non-null name", regClientCommand.getClientName());
+ assertEquals("Unexpected client name", _clientJmsDelegate.getClientName(), regClientCommand.getClientName());
+ assertNotNull("Client queue name should not be null", regClientCommand.getClientQueueName());
+ }
+
+ public void testClientSendsCommandResponses() throws Exception
+ {
+ final RegisterClientCommand registrationCommand = _controllerQueue.getNext();
+ createClientQueueProducer(registrationCommand);
+
+ sendCommandToClient(new NoOpCommand());
+
+ final Response responseCommand = _controllerQueue.getNext();
+ assertEquals("Incorrect client message type", CommandType.RESPONSE, responseCommand.getType());
+ }
+
+ public void testClientCanBeStoppedViaCommand() throws Exception
+ {
+ assertEquals("Expected client to be in STARTED state", ClientState.READY, _client.getState());
+
+ final RegisterClientCommand registrationCommand = _controllerQueue.getNext();
+ createClientQueueProducer(registrationCommand);
+
+ final Command stopClientCommand = new StopClientCommand();
+ sendCommandToClient(stopClientCommand);
+
+ _client.waitUntilStopped(1000);
+
+ Response response = _controllerQueue.getNext();
+ assertNotNull(response);
+ assertFalse("response shouldn't contain error", response.hasError());
+
+ assertEquals("Expected client to be in STOPPED state", ClientState.STOPPED, _client.getState());
+ }
+
+ public void testClientCanCreateTestConnection() throws Exception
+ {
+ assertEquals("Unexpected number of test connections", 0, _clientJmsDelegate.getNoOfTestConnections());
+
+ final RegisterClientCommand registration = _controllerQueue.getNext();
+ createClientQueueProducer(registration);
+
+ final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand();
+ createConnectionCommand.setConnectionName("newTestConnection");
+ createConnectionCommand.setConnectionFactoryName("connectionfactory");
+
+ sendCommandToClient(createConnectionCommand);
+ Response response = _controllerQueue.getNext();
+
+ assertFalse("Response message should not have indicated an error", response.hasError());
+ assertEquals("Unexpected number of test connections", 1, _clientJmsDelegate.getNoOfTestConnections());
+ }
+
+ public void testClientCanCreateTestSession() throws Exception
+ {
+ assertEquals("Unexpected number of test sessions", 0, _clientJmsDelegate.getNoOfTestSessions());
+
+ final RegisterClientCommand registration = _controllerQueue.getNext();
+ createClientQueueProducer(registration);
+
+ final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand();
+ createConnectionCommand.setConnectionName("newTestConnection");
+ createConnectionCommand.setConnectionFactoryName("connectionfactory");
+
+ sendCommandToClient(createConnectionCommand);
+ Response response = _controllerQueue.getNext();
+ assertFalse("Response message should not have indicated an error", response.hasError());
+
+ final CreateSessionCommand createSessionCommand = new CreateSessionCommand();
+ createSessionCommand.setConnectionName("newTestConnection");
+ createSessionCommand.setSessionName("newTestSession");
+ createSessionCommand.setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
+
+ sendCommandToClient(createSessionCommand);
+ response = _controllerQueue.getNext();
+
+ assertFalse("Response message should not have indicated an error", response.hasError());
+ assertEquals("Unexpected number of test sessions", 1, _clientJmsDelegate.getNoOfTestSessions());
+ }
+
+ private void sendCommandToClient(final Command command) throws JMSException
+ {
+ final Message message = JmsMessageAdaptor.commandToMessage(_session, command);
+ _clientQueueProducer.send(message);
+ }
+
+ private void createClientQueueProducer(
+ final RegisterClientCommand registration) throws JMSException
+ {
+ final Destination clientCommandQueue = createDestinationFromRegistration(registration);
+ _clientQueueProducer = _session.createProducer(clientCommandQueue);
+ }
+
+ private Queue createDestinationFromRegistration(
+ final RegisterClientCommand registrationCommand)
+ throws JMSException
+ {
+ String clientQueueName = registrationCommand.getClientQueueName();
+ assertNotNull("Null client queue in register message", clientQueueName);
+ return _session.createQueue(clientQueueName);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java
new file mode 100644
index 0000000000..a3c0430865
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.systest.disttest.clientonly;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.ConsumerParticipant;
+import org.apache.qpid.disttest.client.ParticipantExecutor;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+import org.apache.qpid.systest.disttest.clientonly.ProducerParticipantTest.TestClientJmsDelegate;
+
+public class ConsumerParticipantTest extends DistributedTestSystemTestBase
+{
+ private MessageProducer _producer;
+ private Session _session;
+ private TestClientJmsDelegate _delegate;
+ private Client _client;
+ private ControllerQueue _controllerQueue;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _controllerQueue = new ControllerQueue(_connection, _context);
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _producer = _session.createProducer(getTestQueue());
+
+ _delegate = new TestClientJmsDelegate(getContext());
+ _client = new Client(_delegate);
+ }
+
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ _controllerQueue.close();
+ super.tearDown();
+ }
+
+ public void testConsumeNumberOfMessagesSynchronously() throws Exception
+ {
+ runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, true);
+ }
+
+ public void testConsumeNumberOfMessagesAsynchronously() throws Exception
+ {
+ runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, false);
+ }
+
+ public void testSelectors() throws Exception
+ {
+ final CreateConsumerCommand command = new CreateConsumerCommand();
+ command.setNumberOfMessages(10);
+ command.setSessionName("testSession");
+ command.setDestinationName(getTestQueueName());
+ command.setSelector("id=1");
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _delegate.addConnection("name-does-not-matter", _connection);
+ _delegate.addSession(command.getSessionName(), session);
+
+ ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command);
+ _delegate.createConsumer(command);
+
+ for (int i = 0; i < 20; i++)
+ {
+ Message message = _session.createMessage();
+ if (i % 2 == 0)
+ {
+ message.setIntProperty("id", 0);
+ }
+ else
+ {
+ message.setIntProperty("id", 1);
+ }
+ _producer.send(message);
+ }
+
+ new ParticipantExecutor(consumerParticipant).start(_client);
+
+ ParticipantResult results = _controllerQueue.getNext();
+ assertNotNull("No results message recieved", results);
+ assertEquals("Unexpected number of messages received", 10, results.getNumberOfMessagesProcessed());
+
+ Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue());
+ for (int i = 0; i < 10; i++)
+ {
+ Message message = testQueueConsumer.receive(2000);
+ assertNotNull("Message is not received: " + message, message);
+ assertEquals("Unexpected id value", 0, message.getIntProperty("id"));
+ }
+ Message message = testQueueConsumer.receive(2000);
+ assertNull("Unexpected message remaining on test queue: " + message, message);
+
+ _connection.stop();
+ }
+
+ protected void runTest(int acknowledgeMode, int numberOfMessages, int batchSize, boolean synchronous) throws Exception
+ {
+ final CreateConsumerCommand command = new CreateConsumerCommand();
+ command.setNumberOfMessages(numberOfMessages);
+ command.setBatchSize(batchSize);
+ command.setSessionName("testSession");
+ command.setDestinationName(getTestQueueName());
+ command.setSynchronous(synchronous);
+
+ Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode);
+
+ _delegate.addConnection("name-does-not-matter", _connection);
+ _delegate.addSession(command.getSessionName(), session);
+
+ ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command);
+ _delegate.createConsumer(command);
+
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ _producer.send(_session.createMessage());
+ }
+
+ new ParticipantExecutor(consumerParticipant).start(_client);
+
+ ParticipantResult results = _controllerQueue.getNext();
+ assertNotNull("No results message recieved", results);
+
+ Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue());
+ Message message = testQueueConsumer.receive(2000);
+ assertNull("Unexpected message remaining on test queue: " + message, message);
+
+ _connection.stop();
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java
new file mode 100644
index 0000000000..7f0c23eb38
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java
@@ -0,0 +1,90 @@
+package org.apache.qpid.systest.disttest.clientonly;
+
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.naming.Context;
+
+import junit.framework.Assert;
+
+import org.apache.qpid.disttest.DistributedTestConstants;
+import org.apache.qpid.disttest.jms.JmsMessageAdaptor;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+
+/**
+ * Helper for unit tests to simplify access to the Controller Queue.
+ *
+ * Implicitly creates the queue, so you must create a {@link ControllerQueue} object before
+ * trying to use the underlying queue.
+ */
+public class ControllerQueue
+{
+ private MessageConsumer _controllerQueueMessageConsumer;
+ private Session _controllerQueueSession;
+
+ /**
+ * Implicitly creates the queue, so you must create a {@link ControllerQueue} object before
+ * trying to use the underlying queue.
+ *
+ * @param context used for looking up the controller queue {@link Destination}
+ */
+ public ControllerQueue(Connection connection, Context context) throws Exception
+ {
+ _controllerQueueSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Destination controllerQueue = (Destination) context.lookup(DistributedTestConstants.CONTROLLER_QUEUE_JNDI_NAME);
+ _controllerQueueMessageConsumer = _controllerQueueSession.createConsumer(controllerQueue);
+ }
+
+ public <T extends Command> T getNext(long timeout) throws JMSException
+ {
+ final Message message = _controllerQueueMessageConsumer.receive(timeout);
+ if(message == null)
+ {
+ return null;
+ }
+
+ return (T) JmsMessageAdaptor.messageToCommand(message);
+ }
+
+ public void addNextResponse(Map<CommandType, Command> responses) throws JMSException
+ {
+ Command nextResponse = getNext();
+ responses.put(nextResponse.getType(), nextResponse);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Command> T getNext() throws JMSException
+ {
+ return (T)getNext(true);
+ }
+
+ public <T extends Command> T getNext(boolean assertMessageExists) throws JMSException
+ {
+ final Message message = _controllerQueueMessageConsumer.receive(1000);
+ if(assertMessageExists)
+ {
+ Assert.assertNotNull("No message received from control queue", message);
+ }
+
+ if(message == null)
+ {
+ return null;
+ }
+
+ T command = (T) JmsMessageAdaptor.messageToCommand(message);
+
+ return command;
+ }
+
+ public void close() throws Exception
+ {
+ _controllerQueueMessageConsumer.close();
+ _controllerQueueSession.close();
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java
new file mode 100644
index 0000000000..4a872a7ee2
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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.systest.disttest.clientonly;
+
+import static org.apache.qpid.disttest.client.ClientState.READY;
+import static org.apache.qpid.disttest.client.ClientState.RUNNING_TEST;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.ClientState;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.jms.JmsMessageAdaptor;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.CreateConnectionCommand;
+import org.apache.qpid.disttest.message.CreateConsumerCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.CreateSessionCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.disttest.message.StartTestCommand;
+import org.apache.qpid.disttest.message.TearDownTestCommand;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+
+public class DistributedClientTest extends DistributedTestSystemTestBase
+{
+ private static final String TEST_CONSUMER = "newTestConsumer";
+ private static final String TEST_DESTINATION = "newDestination";
+ private static final String TEST_PRODUCER_NAME = "newTestProducer";
+ private static final String TEST_SESSION_NAME = "newTestSession";
+ private static final String TEST_CONNECTION_NAME = "newTestConnection";
+
+ private Session _session = null;
+ private MessageProducer _clientQueueProducer;
+ private Client _client;
+ private ControllerQueue _controllerQueue;
+ protected ClientJmsDelegate _clientJmsDelegate;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _controllerQueue = new ControllerQueue(_connection, _context);
+
+ _clientJmsDelegate = new ClientJmsDelegate(_context);
+ _client = new Client(_clientJmsDelegate);
+ _client.start();
+
+ final RegisterClientCommand registrationCommand = _controllerQueue.getNext();
+ createClientQueueProducer(registrationCommand);
+
+ createTestConnection(TEST_CONNECTION_NAME);
+ createTestSession(TEST_CONNECTION_NAME, TEST_SESSION_NAME);
+
+ assertEquals("Expected no test producers at start of test", 0, _clientJmsDelegate.getNoOfTestProducers());
+ assertEquals("Expected no test consumers at start of test", 0, _clientJmsDelegate.getNoOfTestConsumers());
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ _controllerQueue.close();
+ if (_session != null)
+ {
+ _session.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testClientCanCreateTestProducer() throws Exception
+ {
+ assertEquals("Should initially have zero producers", 0, _clientJmsDelegate.getNoOfTestProducers());
+
+ createTestProducer(TEST_SESSION_NAME, TEST_PRODUCER_NAME, TEST_DESTINATION);
+
+ assertEquals("Should now have one test producer", 1, _clientJmsDelegate.getNoOfTestProducers());
+ }
+
+ public void testClientCanCreateTestConsumer() throws Exception
+ {
+ assertEquals("Should initially have no test consumers", 0, _clientJmsDelegate.getNoOfTestConsumers());
+
+ createTestConsumer(TEST_SESSION_NAME, TEST_CONSUMER, TEST_DESTINATION);
+
+ assertEquals("Should now have one test consumer", 1, _clientJmsDelegate.getNoOfTestConsumers());
+ }
+
+ public void testClientFailsToCreateSessionUsingInvalidConnection() throws Exception
+ {
+ int initialNoOfTestSessions = _clientJmsDelegate.getNoOfTestSessions();
+
+ createTestSession("nonExistentConnection", TEST_SESSION_NAME, false /* shouldSucceed */);
+
+ assertEquals("Number of test sessions should not have changed", initialNoOfTestSessions, _clientJmsDelegate.getNoOfTestSessions());
+ }
+
+ public void testClientFailsToCreateProducerUsingInvalidSession() throws Exception
+ {
+ int initialNoOfTestProducers = _clientJmsDelegate.getNoOfTestProducers();
+
+ createTestProducer("invalidSessionName", TEST_PRODUCER_NAME, TEST_DESTINATION, false /* shouldSucceed */);
+
+ assertEquals("Number of test producers should not have changed", initialNoOfTestProducers, _clientJmsDelegate.getNoOfTestProducers());
+ }
+
+ public void testClientFailsToCreateConsumerUsingInvalidSession() throws Exception
+ {
+ int initialNoOfTestConsumers = _clientJmsDelegate.getNoOfTestConsumers();
+
+ createTestConsumer("invalidSessionName", TEST_CONSUMER, TEST_DESTINATION, false /* shouldSucceed */);
+
+ assertEquals("Number of test consumers should not have changed", initialNoOfTestConsumers, _clientJmsDelegate.getNoOfTestConsumers());
+ }
+
+ public void testClientCanStartPerformingTests() throws Exception
+ {
+ createTestProducer(TEST_SESSION_NAME, TEST_PRODUCER_NAME, TEST_DESTINATION);
+
+ sendCommandToClient(new StartTestCommand());
+
+ validateStartTestResponseAndParticipantResults(CommandType.PRODUCER_PARTICIPANT_RESULT);
+
+ assertState(_client, RUNNING_TEST);
+ }
+
+ public void testParticipantsSendResults() throws JMSException
+ {
+ createTestProducer(TEST_SESSION_NAME, TEST_PRODUCER_NAME, TEST_DESTINATION);
+
+ sendCommandToClient(new StartTestCommand());
+
+ validateStartTestResponseAndParticipantResults(CommandType.PRODUCER_PARTICIPANT_RESULT);
+ }
+
+ /**
+ * Need to validate both of these responses together because their order is non-deterministic
+ * @param expectedParticipantResultCommandType TODO
+ */
+ private void validateStartTestResponseAndParticipantResults(CommandType expectedParticipantResultCommandType) throws JMSException
+ {
+ Map<CommandType, Command> responses = new HashMap<CommandType, Command>();
+ _controllerQueue.addNextResponse(responses);
+ _controllerQueue.addNextResponse(responses);
+
+ ParticipantResult results = (ParticipantResult) responses.get(expectedParticipantResultCommandType);
+ validateResponse(null, results, true);
+
+ Response startTestResponse = (Response) responses.get(CommandType.RESPONSE);
+ validateResponse(CommandType.START_TEST, startTestResponse, true);
+ }
+
+ public void testClientCannotStartPerformingTestsInNonReadyState() throws Exception
+ {
+ assertState(_client, READY);
+ sendCommandAndValidateResponse(new StartTestCommand(), true);
+ assertState(_client, RUNNING_TEST);
+
+ // Send another start test command
+ sendCommandAndValidateResponse(new StartTestCommand(), false /*should reject duplicate start command*/);
+ assertState(_client, RUNNING_TEST);
+ }
+
+ public void testNonRunningClientIsUnaffectedByStopTestCommand() throws Exception
+ {
+ assertState(_client, READY);
+
+ sendCommandAndValidateResponse(new TearDownTestCommand(), false);
+
+ assertState(_client, READY);
+ }
+
+ private void sendCommandToClient(final Command command) throws JMSException
+ {
+ final Message message = JmsMessageAdaptor.commandToMessage(_session, command);
+ _clientQueueProducer.send(message);
+ }
+
+ private void sendCommandAndValidateResponse(final Command command, boolean shouldSucceed) throws JMSException
+ {
+ sendCommandToClient(command);
+ Response response = _controllerQueue.getNext();
+ validateResponse(command.getType(), response, shouldSucceed);
+ }
+
+ private void sendCommandAndValidateResponse(final Command command) throws JMSException
+ {
+ sendCommandAndValidateResponse(command, true);
+ }
+
+ private void createTestConnection(String connectionName) throws Exception
+ {
+ int initialNumberOfConnections = _clientJmsDelegate.getNoOfTestConnections();
+
+ final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand();
+ createConnectionCommand.setConnectionName(connectionName);
+ createConnectionCommand.setConnectionFactoryName("connectionfactory");
+
+ sendCommandAndValidateResponse(createConnectionCommand);
+
+ int expectedNumberOfConnections = initialNumberOfConnections + 1;
+
+ assertEquals("unexpected number of test connections", expectedNumberOfConnections, _clientJmsDelegate.getNoOfTestConnections());
+ }
+
+ private void createTestSession(String connectionName, String sessionName, boolean shouldSucceed) throws Exception
+ {
+ int initialNumberOfSessions = _clientJmsDelegate.getNoOfTestSessions();
+
+ final CreateSessionCommand createSessionCommand = new CreateSessionCommand();
+ createSessionCommand.setConnectionName(connectionName);
+ createSessionCommand.setSessionName(sessionName);
+ createSessionCommand.setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
+
+ sendCommandAndValidateResponse(createSessionCommand, shouldSucceed);
+
+ int expectedNumberOfSessions = initialNumberOfSessions + (shouldSucceed ? 1 : 0);
+
+ assertEquals("unexpected number of test sessions", expectedNumberOfSessions, _clientJmsDelegate.getNoOfTestSessions());
+ }
+
+ private void createTestSession(String connectionName, String sessionName) throws Exception
+ {
+ createTestSession(connectionName, sessionName, true);
+ }
+
+ private void createTestProducer(String sessionName, String producerName, String destinationName, boolean shouldSucceed) throws JMSException
+ {
+ final CreateProducerCommand createProducerCommand = new CreateProducerCommand();
+ createProducerCommand.setParticipantName(producerName);
+ createProducerCommand.setSessionName(sessionName);
+ createProducerCommand.setDestinationName(destinationName);
+ createProducerCommand.setNumberOfMessages(100);
+
+ sendCommandAndValidateResponse(createProducerCommand, shouldSucceed);
+ }
+
+ private void createTestProducer(String sessionName, String producerName, String destinationName) throws JMSException
+ {
+ createTestProducer(sessionName, producerName, destinationName, true);
+ }
+
+ private void createTestConsumer(String sessionName, String consumerName, String destinationName, boolean shouldSucceed) throws JMSException
+ {
+ final CreateConsumerCommand createConsumerCommand = new CreateConsumerCommand();
+ createConsumerCommand.setSessionName(sessionName);
+ createConsumerCommand.setDestinationName(destinationName);
+ createConsumerCommand.setParticipantName(consumerName);
+ createConsumerCommand.setNumberOfMessages(1);
+
+ sendCommandAndValidateResponse(createConsumerCommand, shouldSucceed);
+ }
+
+ private void createTestConsumer(String sessionName, String consumerName, String destinationName) throws JMSException
+ {
+ createTestConsumer(sessionName, consumerName, destinationName, true);
+ }
+
+ private void validateResponse(CommandType originatingCommandType, Response response, boolean shouldSucceed) throws JMSException
+ {
+ assertEquals("Response is a reply to the wrong command: " + response,
+ originatingCommandType,
+ response.getInReplyToCommandType());
+
+ boolean shouldHaveError = !shouldSucceed;
+ assertEquals("Response message " + response + " should have indicated hasError=" + shouldHaveError,
+ shouldHaveError,
+ response.hasError());
+ }
+
+ private void createClientQueueProducer(final RegisterClientCommand registration) throws JMSException
+ {
+ final Destination clientCommandQueue = createDestinationFromRegistration(registration);
+ _clientQueueProducer = _session.createProducer(clientCommandQueue);
+ }
+
+ private Queue createDestinationFromRegistration(final RegisterClientCommand registrationCommand) throws JMSException
+ {
+ String clientQueueName = registrationCommand.getClientQueueName();
+ assertNotNull("Null client queue in register message", clientQueueName);
+ return _session.createQueue(clientQueueName);
+ }
+
+ private static void assertState(Client client, ClientState expectedState)
+ {
+ ClientState clientState = client.getState();
+ assertEquals("Client should be in state: " + expectedState + " but is in state " + clientState, expectedState, clientState);
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java
new file mode 100644
index 0000000000..dcbff6518b
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.disttest.clientonly;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.disttest.client.MessageProvider;
+import org.apache.qpid.disttest.client.property.PropertyValue;
+import org.apache.qpid.disttest.client.property.SimplePropertyValue;
+import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+import org.apache.qpid.systest.disttest.clientonly.ProducerParticipantTest.TestClientJmsDelegate;
+
+public class MessageProviderTest extends DistributedTestSystemTestBase
+{
+ private MessageConsumer _consumer;
+ private Session _session;
+ private TestClientJmsDelegate _delegate;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _consumer = _session.createConsumer(getTestQueue());
+ _delegate = new TestClientJmsDelegate(getContext());
+ }
+
+ public void testMessageSize() throws Exception
+ {
+ runSizeTest(0);
+ runSizeTest(5);
+ runSizeTest(512);
+ }
+
+ public void runSizeTest(int size) throws Exception
+ {
+ CreateProducerCommand command = new CreateProducerCommand();
+ command.setMessageSize(size);
+ MessageProvider messageProvider = new MessageProvider(null);
+ Message message = messageProvider.nextMessage(_session, command);
+ assertNotNull("Message is not generated", message);
+ assertTrue("Wrong message type", message instanceof TextMessage);
+ TextMessage textMessage = (TextMessage)message;
+ String text = textMessage.getText();
+ assertNotNull("Message payload is not generated", text);
+ assertEquals("Message payload size is incorrect", size, text.length());
+ }
+
+ public void testCreateMessageProviderAndSendMessage() throws Exception
+ {
+ final CreateMessageProviderCommand messageProviderCommand = new CreateMessageProviderCommand();
+ messageProviderCommand.setProviderName("test1");
+ Map<String, PropertyValue> messageProperties = new HashMap<String, PropertyValue>();
+ messageProperties.put("test", new SimplePropertyValue("testValue"));
+ messageProperties.put("priority", new SimplePropertyValue(new Integer(9)));
+ messageProviderCommand.setMessageProperties(messageProperties);
+ _delegate.createMessageProvider(messageProviderCommand);
+
+ final CreateProducerCommand producerCommand = new CreateProducerCommand();
+ producerCommand.setNumberOfMessages(1);
+ producerCommand.setDeliveryMode(DeliveryMode.PERSISTENT);
+ producerCommand.setPriority(6);
+ producerCommand.setParticipantName("test");
+ producerCommand.setMessageSize(10);
+ producerCommand.setSessionName("testSession");
+ producerCommand.setDestinationName(getTestQueueName());
+ producerCommand.setMessageProviderName(messageProviderCommand.getProviderName());
+
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _delegate.addConnection("name-does-not-matter", _connection);
+ _delegate.addSession(producerCommand.getSessionName(), session);
+ _delegate.createProducer(producerCommand);
+
+ Message message = _delegate.sendNextMessage(producerCommand);
+ session.commit();
+ assertMessage(message);
+
+ _connection.start();
+ Message receivedMessage = _consumer.receive(1000l);
+ assertMessage(receivedMessage);
+ }
+
+ protected void assertMessage(Message message) throws JMSException
+ {
+ assertNotNull("Message should not be null", message);
+ assertEquals("Unexpected test property", "testValue", message.getStringProperty("test"));
+ assertEquals("Unexpected priority property", 9, message.getJMSPriority());
+ assertTrue("Unexpected message type", message instanceof TextMessage);
+ String text = ((TextMessage)message).getText();
+ assertNotNull("Message text should not be null", text);
+ assertNotNull("Unexpected message size ", text.length());
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java
new file mode 100644
index 0000000000..54bb9efa98
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.systest.disttest.clientonly;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.ParticipantExecutor;
+import org.apache.qpid.disttest.client.ProducerParticipant;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.message.CreateProducerCommand;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+
+public class ProducerParticipantTest extends DistributedTestSystemTestBase
+{
+ private MessageConsumer _consumer;
+ private TestClientJmsDelegate _delegate;
+ private Client _client;
+ private ControllerQueue _controllerQueue;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _controllerQueue = new ControllerQueue(_connection, _context);
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _consumer = session.createConsumer(getTestQueue());
+
+ _delegate = new TestClientJmsDelegate(getContext());
+ _client = new Client(_delegate);
+ }
+
+
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ _controllerQueue.close();
+ super.tearDown();
+ }
+
+
+
+ public void testProduceNumberOfMessages() throws Exception
+ {
+ runTest(Session.AUTO_ACKNOWLEDGE, 100, 10, 0, 0);
+ }
+
+ protected void runTest(int acknowledgeMode, int messageSize, int numberOfMessages, int batchSize, long publishInterval) throws Exception
+ {
+ final CreateProducerCommand command = new CreateProducerCommand();
+ command.setNumberOfMessages(numberOfMessages);
+ command.setDeliveryMode(DeliveryMode.PERSISTENT);
+ command.setParticipantName("test");
+ command.setMessageSize(messageSize);
+ command.setBatchSize(batchSize);
+ command.setInterval(publishInterval);
+ command.setSessionName("testSession");
+ command.setDestinationName(getTestQueueName());
+
+ Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode);
+
+ _delegate.addConnection("name-does-not-matter", _connection);
+ _delegate.addSession(command.getSessionName(), session);
+ _delegate.createProducer(command);
+
+ final ProducerParticipant producer = new ProducerParticipant(_delegate, command);
+
+ new ParticipantExecutor(producer).start(_client);
+
+ _connection.start();
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = _consumer.receive(1000l);
+ assertNotNull("Expected message [" + i + "] is not received", m);
+ assertTrue("Unexpected message", m instanceof TextMessage);
+ }
+ Message m = _consumer.receive(500l);
+ assertNull("Unexpected message", m);
+
+ ParticipantResult results = _controllerQueue.getNext();
+
+ assertNotNull("no results", results);
+ assertFalse(results.getStartInMillis() == 0);
+ assertFalse(results.getEndInMillis() == 0);
+ }
+
+ static class TestClientJmsDelegate extends ClientJmsDelegate
+ {
+
+ public TestClientJmsDelegate(Context context)
+ {
+ super(context);
+ }
+
+ @Override
+ public void addSession(final String sessionName, final Session newSession)
+ {
+ super.addSession(sessionName, newSession);
+ }
+
+ @Override
+ public void addConnection(final String connectionName, final Connection newConnection)
+ {
+ super.addConnection(connectionName, newConnection);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java
new file mode 100644
index 0000000000..e8790ea7f6
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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.systest.disttest.controllerandclient;
+
+import static org.apache.qpid.systest.disttest.SystemTestConstants.COMMAND_RESPONSE_TIMEOUT;
+import static org.apache.qpid.systest.disttest.SystemTestConstants.REGISTRATION_TIMEOUT;
+import static org.apache.qpid.systest.disttest.SystemTestConstants.TEST_RESULT_TIMEOUT;
+
+import java.util.List;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.NamingException;
+
+import org.apache.qpid.disttest.ConfigFileHelper;
+import org.apache.qpid.disttest.client.Client;
+import org.apache.qpid.disttest.client.ClientState;
+import org.apache.qpid.disttest.controller.Controller;
+import org.apache.qpid.disttest.controller.ResultsForAllTests;
+import org.apache.qpid.disttest.controller.TestResult;
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.jms.ClientJmsDelegate;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.message.ConsumerParticipantResult;
+import org.apache.qpid.disttest.message.ParticipantResult;
+import org.apache.qpid.disttest.message.ProducerParticipantResult;
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+
+public class ControllerAndClientTest extends DistributedTestSystemTestBase
+{
+ private Controller _controller;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _controller = new Controller(new ControllerJmsDelegate(_context), REGISTRATION_TIMEOUT, COMMAND_RESPONSE_TIMEOUT);
+ _controller.setTestResultTimeout(TEST_RESULT_TIMEOUT);
+ }
+
+ public void testProducerAndConsumerInSeparateClients() throws Exception
+ {
+ List<TestResult> resultList = runTestsForTwoClients("producerAndConsumerInSeparateClients.json", 1);
+
+ TestResult testResult1 = resultList.get(0);
+ assertEquals("Unexpected test name", "Test 1", testResult1.getName());
+ List<ParticipantResult> test1ParticipantResults = testResult1.getParticipantResults();
+ assertEquals("Unexpected number of participant results for test 1", 2, test1ParticipantResults.size());
+ assertParticipantNames(test1ParticipantResults, "participantConsumer1", "participantProducer1");
+ }
+
+ public void testProducerClient() throws Exception
+ {
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = session.createQueue("producerClient");
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ // queue is not declared in configuration
+ // controller is not able to clean it
+ // cleaning manually
+ while(consumer.receive(1000l) != null);
+
+ final Config config = ConfigFileHelper.getConfigFromResource(getClass(), "produceClient.json");
+ _controller.setConfig(config);
+ final Client client1 = new Client(new ClientJmsDelegate(_context));
+ final Thread client1Thread = createBackgroundClientThread(client1);
+ _controller.awaitClientRegistrations();
+
+ ResultsForAllTests results = _controller.runAllTests();
+ _controller.stopAllRegisteredClients();
+
+ assertClientThreadsShutdown(client1Thread);
+ assertClientsStopped(ClientState.STOPPED, client1);
+ assertFalse("Test should have no errors", results.hasErrors());
+ List<ITestResult> allTestResults = results.getTestResults();
+ assertEquals("Unexpected number of test results", 1, allTestResults.size());
+ ITestResult testResult1 = allTestResults.get(0);
+ assertEquals("Unexpected test name", "Test 1", testResult1.getName());
+ List<ParticipantResult> test1ParticipantResults = testResult1.getParticipantResults();
+ assertEquals("Unexpected number of participant results for test 1", 1, test1ParticipantResults.size());
+ assertParticipantNames(test1ParticipantResults, "participantProducer1");
+
+ // check message properties
+ for (int i=0; i< 10; i++)
+ {
+ Message message = consumer.receive(1000l);
+ assertNotNull("Message " + i + " is not received", message);
+ assertEquals("Unexpected priority", i, message.getJMSPriority());
+ assertEquals("Unexpected id", i, message.getIntProperty("id"));
+ assertEquals("Unexpected test", "test-value", message.getStringProperty("test"));
+ }
+ }
+
+ public void testProducerAndThreeConsumersInSeparateClients() throws Exception
+ {
+ List<TestResult> resultList = runTestsForTwoClients("producerAndThreeConsumersInSeparateClients.json", 1);
+
+ TestResult testResult1 = resultList.get(0);
+ List<ParticipantResult> test1ParticipantResults = testResult1.getParticipantResults();
+ assertEquals("Unexpected number of participant results for test", 4, test1ParticipantResults.size());
+
+ assertParticipantNames(test1ParticipantResults, "participantConsumer1", "participantConsumer2", "participantConsumer3", "participantProducer1");
+
+ ConsumerParticipantResult consumer1 = (ConsumerParticipantResult) test1ParticipantResults.get(0);
+ assertEquals(3, consumer1.getNumberOfMessagesProcessed());
+ assertEquals(true, consumer1.isSynchronousConsumer());
+
+ ProducerParticipantResult producer1 = (ProducerParticipantResult) test1ParticipantResults.get(3);
+ assertEquals(9, producer1.getNumberOfMessagesProcessed());
+ assertEquals(2, producer1.getBatchSize());
+ assertEquals(50, producer1.getInterval());
+ }
+
+ public void testIteratingFeature() throws Exception
+ {
+ List<TestResult> resultList = runTestsForTwoClients("iteratingFeature.json", 2);
+
+ assertTestResultMessageSize(resultList.get(0), 0, 100, 10);
+ assertTestResultMessageSize(resultList.get(1), 1, 200, 5);
+
+ }
+
+ private void assertTestResultMessageSize(TestResult testResult, int iterationNumber, int expectedMessageSize, int expectedNumberOfMessages)
+ {
+ List<ParticipantResult> test1ParticipantResults = testResult.getParticipantResults();
+ assertEquals("Unexpected number of participant results for test", 2, test1ParticipantResults.size());
+
+ ParticipantResult producer1 = (ParticipantResult) test1ParticipantResults.get(1);
+
+ assertEquals(expectedMessageSize, producer1.getPayloadSize());
+ assertEquals(iterationNumber, producer1.getIterationNumber());
+ }
+
+ public void testTwoTests() throws Exception
+ {
+ List<TestResult> resultList = runTestsForTwoClients("testWithTwoTests.json", 2);
+
+ assertEquals("Test 1", resultList.get(0).getName());
+ assertEquals("Test 2", resultList.get(1).getName());
+ }
+
+ private List<TestResult> runTestsForTwoClients(String jsonConfigFile, int expectedNumberOfTests) throws NamingException, InterruptedException
+ {
+ final Config config = ConfigFileHelper.getConfigFromResource(getClass(), jsonConfigFile);
+ _controller.setConfig(config);
+
+ final Client client1 = new Client(new ClientJmsDelegate(_context));
+ final Client client2 = new Client(new ClientJmsDelegate(_context));
+
+ final Thread client1Thread = createBackgroundClientThread(client1);
+ final Thread client2Thread = createBackgroundClientThread(client2);
+
+ _controller.awaitClientRegistrations();
+
+ ResultsForAllTests results = _controller.runAllTests();
+ _controller.stopAllRegisteredClients();
+
+ assertClientThreadsShutdown(client1Thread, client2Thread);
+ assertClientsStopped(ClientState.STOPPED, client1, client2);
+
+ assertFalse("Test should have no errors", results.hasErrors());
+
+ List<TestResult> allTestResults = (List)results.getTestResults();
+ assertEquals("Unexpected number of test results", expectedNumberOfTests, allTestResults.size());
+
+ return allTestResults;
+ }
+
+
+ private void assertParticipantNames(List<ParticipantResult> participants, String... expectedOrderedParticipantNames)
+ {
+ assertEquals("Size of list of expected participant names is different from actual", expectedOrderedParticipantNames.length, participants.size());
+
+ for (int i = 0; i < expectedOrderedParticipantNames.length; i++)
+ {
+ String expectedParticipantName = expectedOrderedParticipantNames[i];
+ ParticipantResult participant = participants.get(i);
+ assertEquals(expectedParticipantName, participant.getParticipantName());
+ }
+ }
+
+ private void assertClientsStopped(ClientState expectedState, final Client... clients)
+ {
+ for (Client client : clients)
+ {
+ assertEquals(client.getClientName() + " in unexpected state", expectedState, client.getState());
+ }
+ }
+
+ private void assertClientThreadsShutdown(final Thread... clientThreads)
+ throws InterruptedException
+ {
+ for (Thread clientThread : clientThreads)
+ {
+ clientThread.join(2000);
+ assertFalse(clientThread.getName() + " should have shutdown", clientThread.isAlive());
+ }
+ }
+
+ private Thread createBackgroundClientThread(final Client client) throws NamingException
+ {
+ final String clientThreadName = client.getClientName() + "-thread";
+ final Thread clientThread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ client.start();
+ client.waitUntilStopped(1000);
+ }
+ }, clientThreadName);
+ clientThread.start();
+ return clientThread;
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json
new file mode 100644
index 0000000000..89123302b7
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json
@@ -0,0 +1,63 @@
+{
+ "_tests":[
+ {
+ "_name": "Test iteration feature",
+ "_iterations":[
+ {
+ "_messageSize": 100,
+ "_numberOfMessages": 10
+ },
+ {
+ "_messageSize": 200,
+ "_numberOfMessages": 5
+ }
+ ],
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue"
+ }
+ ],
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//testQueue"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantConsumer1",
+ "_destinationName": "direct://amq.direct//testQueue"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json
new file mode 100644
index 0000000000..605e5cb585
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json
@@ -0,0 +1,41 @@
+{
+ "_tests":[
+ {
+ "_name": "Test 1";
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//producerClient",
+ "_numberOfMessages": 10;
+ "_messageProviderName": "testProvider1"
+ }
+ ]
+ }
+ ]
+ }
+ ];
+ "_messageProviders":[
+ {
+ "_name": "testProvider1";
+ "_messageProperties": {
+ "priority": {"@def": "list"; "_items": [0,1,2,3,4,5,6,7,8,9]};
+ "id": {"@def": "range"; "_upper": 10; "_type": "int"};
+ "test": "test-value"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json
new file mode 100644
index 0000000000..8d210dce84
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json
@@ -0,0 +1,55 @@
+{
+ "_tests":[
+ {
+ "_name": "Test 1";
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue"
+ }
+ ];
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantConsumer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json
new file mode 100644
index 0000000000..f94c4f0ae0
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json
@@ -0,0 +1,77 @@
+{
+ "_tests":[
+ {
+ "_name": "ProducerAndThreeConsumersInSeparateClients";
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue"
+ }
+ ];
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 9,
+ "_batchSize": 2,
+ "_interval": 50
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantConsumer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 3
+ }
+ ]
+ },
+ {
+ "_sessionName": "session2",
+ "_consumers": [
+ {
+ "_name": "participantConsumer2",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 3
+ }
+ ]
+ },
+ {
+ "_sessionName": "session3",
+ "_consumers": [
+ {
+ "_name": "participantConsumer3",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 3
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json
new file mode 100644
index 0000000000..4abd7f4feb
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json
@@ -0,0 +1,107 @@
+{
+ "_tests":[
+ {
+ "_name": "Test 1";
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue"
+ }
+ ];
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantconsumer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "Test 2";
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue2"
+ }
+ ];
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer2",
+ "_destinationName": "direct://amq.direct//testQueue2",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantConsumer2",
+ "_destinationName": "direct://amq.direct//testQueue2",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java
new file mode 100644
index 0000000000..ad7f0e0682
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.systest.disttest.controlleronly;
+
+import static org.apache.qpid.systest.disttest.SystemTestConstants.COMMAND_RESPONSE_TIMEOUT;
+import static org.apache.qpid.systest.disttest.SystemTestConstants.REGISTRATION_TIMEOUT;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+
+import org.apache.qpid.disttest.ConfigFileHelper;
+import org.apache.qpid.disttest.controller.Controller;
+import org.apache.qpid.disttest.controller.config.Config;
+import org.apache.qpid.disttest.jms.ControllerJmsDelegate;
+import org.apache.qpid.disttest.jms.JmsMessageAdaptor;
+import org.apache.qpid.disttest.message.Command;
+import org.apache.qpid.disttest.message.CommandType;
+import org.apache.qpid.disttest.message.RegisterClientCommand;
+import org.apache.qpid.disttest.message.Response;
+import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DistributedControllerTest extends DistributedTestSystemTestBase
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(DistributedControllerTest.class);
+
+ private static final String CLIENT1 = "client1";
+ private Controller _controller = null;
+ private Session _session = null;
+ private Connection _connection = null;
+ private Destination _controllerQueue = null;
+ private TemporaryQueue _clientQueue = null;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _controllerQueue = (Destination) _context.lookup("controllerqueue");
+
+ final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory");
+ _connection = connectionFactory.createConnection();
+ _connection.start();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _clientQueue = _session.createTemporaryQueue();
+
+ _controller = new Controller(new ControllerJmsDelegate(_context), REGISTRATION_TIMEOUT, COMMAND_RESPONSE_TIMEOUT);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testControllerSendsOneCommandToSingleClient() throws Exception
+ {
+ Config config = ConfigFileHelper.getConfigFromResource(getClass(), "distributedControllerTest.json");
+ _controller.setConfig(config);
+
+ sendRegistration(CLIENT1);
+ _controller.awaitClientRegistrations();
+
+ final ArrayBlockingQueue<Command> commandList = new ArrayBlockingQueue<Command>(4);
+ final MessageConsumer clientConsumer = _session.createConsumer(_clientQueue);
+ final AtomicReference<Exception> listenerException = new AtomicReference<Exception>();
+ final MessageProducer producer = _session.createProducer(_controllerQueue);
+ clientConsumer.setMessageListener(new MessageListener()
+ {
+ @Override
+ public void onMessage(Message message)
+ {
+ try
+ {
+ Command command = JmsMessageAdaptor.messageToCommand(message);
+ LOGGER.debug("Test client received " + command);
+ commandList.add(command);
+ producer.send(JmsMessageAdaptor.commandToMessage(_session, new Response(CLIENT1, command.getType())));
+ }
+ catch(Exception e)
+ {
+ listenerException.set(e);
+ }
+ }
+ });
+
+ _controller.runAllTests();
+ assertCommandType(CommandType.CREATE_CONNECTION, commandList);
+ assertCommandType(CommandType.START_TEST, commandList);
+ assertCommandType(CommandType.TEAR_DOWN_TEST, commandList);
+
+ _controller.stopAllRegisteredClients();
+ assertCommandType(CommandType.STOP_CLIENT, commandList);
+ assertNull("Unexpected exception occured", listenerException.get());
+ Command command = commandList.poll(1l, TimeUnit.SECONDS);
+ assertNull("Unexpected command is received", command);
+ }
+
+ private void assertCommandType(CommandType expectedType, BlockingQueue<Command> commandList) throws InterruptedException
+ {
+ Command command = commandList.poll(1l, TimeUnit.SECONDS);
+ assertNotNull("Command of type " + expectedType + " is not received", command);
+ assertEquals("Unexpected command type", expectedType, command.getType());
+ }
+
+ private void sendRegistration(final String clientId) throws JMSException
+ {
+ final MessageProducer registrationProducer = _session.createProducer(_controllerQueue);
+
+ final Command command = new RegisterClientCommand(clientId, _clientQueue.getQueueName());
+ final Message registrationMessage = JmsMessageAdaptor.commandToMessage(_session, command);
+ registrationProducer.send(registrationMessage);
+ LOGGER.debug("sent registrationMessage: " + registrationMessage);
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json
new file mode 100644
index 0000000000..b49603ef23
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json
@@ -0,0 +1,17 @@
+{
+ "_tests":[
+ {
+ "_name": "Test 1";
+ "_clients":[
+ {
+ "_name": "client1",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory"
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java
new file mode 100644
index 0000000000..c2ec1d6291
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.systest.disttest.endtoend;
+
+import static org.apache.qpid.disttest.AbstractRunner.JNDI_CONFIG_PROP;
+import static org.apache.qpid.disttest.ControllerRunner.OUTPUT_FILE_PROP;
+import static org.apache.qpid.disttest.ControllerRunner.TEST_CONFIG_PROP;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.qpid.disttest.ControllerRunner;
+import org.apache.qpid.disttest.message.ParticipantAttribute;
+import org.apache.qpid.disttest.results.aggregation.TestResultAggregator;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.FileUtils;
+
+public class EndToEndTest extends QpidBrokerTestCase
+{
+ private ControllerRunner _runner;
+ private static final String TEST_CONFIG = "perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json";
+ private static final String JNDI_CONFIG_FILE = "perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties";
+
+ public void testRunner() throws Exception
+ {
+ File csvOutputFile = createTemporaryCsvFile();
+ assertFalse("CSV output file must exist",csvOutputFile.exists());
+
+ final String[] args = new String[] {TEST_CONFIG_PROP + "=" + TEST_CONFIG,
+ JNDI_CONFIG_PROP + "=" + JNDI_CONFIG_FILE,
+ OUTPUT_FILE_PROP + "=" + csvOutputFile.getAbsolutePath()};
+ _runner = new ControllerRunner();
+ _runner.parseArgumentsIntoConfig(args);
+ _runner.runController();
+
+ assertTrue("CSV output file must exist", csvOutputFile.exists());
+ final String csvContents = FileUtils.readFileAsString(csvOutputFile);
+ final String[] csvLines = csvContents.split("\n");
+
+ int numberOfHeaders = 1;
+ int numberOfParticipants = 2;
+ int numberOfSummaries = 3;
+
+ int numberOfExpectedRows = numberOfHeaders + numberOfParticipants + numberOfSummaries;
+ assertEquals("Unexpected number of lines in CSV", numberOfExpectedRows, csvLines.length);
+
+ assertDataRowsHaveCorrectTestAndClientName("End To End 1", "producingClient", "participantProducer1", csvLines[1], 1);
+ assertDataRowsHaveCorrectTestAndClientName("End To End 1", "consumingClient", "participantConsumer1", csvLines[2], 1);
+
+ assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_PARTICIPANTS_NAME, csvLines[3], 1);
+ assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_CONSUMER_PARTICIPANTS_NAME, csvLines[4], 1);
+ assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_PRODUCER_PARTICIPANTS_NAME, csvLines[5], 1);
+
+ }
+
+ private void assertDataRowsHaveCorrectTestAndClientName(String testName, String clientName, String participantName, String csvLine, int expectedNumberOfMessagesProcessed)
+ {
+ final int DONT_STRIP_EMPTY_LAST_FIELD_FLAG = -1;
+ String[] cells = csvLine.split(",", DONT_STRIP_EMPTY_LAST_FIELD_FLAG);
+ // All attributes become cells in the CSV, so this will be true
+ assertEquals("Unexpected number of cells in CSV line " + csvLine, ParticipantAttribute.values().length, cells.length);
+ assertEquals("Unexpected test name in CSV line " + csvLine, testName, cells[0]);
+ assertEquals("Unexpected client name in CSV line " + csvLine, clientName, cells[2]);
+ assertEquals("Unexpected participant name in CSV line " + csvLine, participantName, cells[3]);
+ assertEquals("Unexpected number of messages processed in CSV line " + csvLine, String.valueOf(expectedNumberOfMessagesProcessed), cells[4]);
+
+ }
+
+ private File createTemporaryCsvFile() throws IOException
+ {
+ File csvFile = File.createTempFile(getName(), ".csv");
+ csvFile.delete();
+ csvFile.deleteOnExit();
+
+ return csvFile;
+ }
+
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json
new file mode 100644
index 0000000000..1b7cc51265
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json
@@ -0,0 +1,65 @@
+{
+ "_tests":[
+ {
+ "_name": "End To End 1";
+ "_queues":[
+ {
+ "_name": "direct://amq.direct//testQueue"
+ }
+ ];
+ "_clients":[
+ {
+ "_name": "producingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_producers": [
+ {
+ "_name": "participantProducer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ];
+ "_messageProviders":[
+ {
+ "_name": "testProvider1";
+ "_messageProperties": {
+ "priority": {"@def": "list"; "_items": [1,2,3,4,4]};
+ "id": {"@def": "random"; "_upper": 10};
+ "test": "test-value"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "_name": "consumingClient",
+ "_connections":[
+ {
+ "_name": "connection1",
+ "_factory": "connectionfactory",
+ "_sessions": [
+ {
+ "_sessionName": "session1",
+ "_consumers": [
+ {
+ "_name": "participantConsumer1",
+ "_destinationName": "direct://amq.direct//testQueue",
+ "_numberOfMessages": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }]
+} \ No newline at end of file
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties
new file mode 100644
index 0000000000..b5d053227c
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties
@@ -0,0 +1,26 @@
+# 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.
+
+# this file is used for running system tests of the performance test framework,
+# (i.e. not for running the performance tests themselves!)
+
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+# use QpidBrokerTestCase's default port
+connectionfactory.connectionfactory = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:15672'
+
+destination.controllerqueue = direct://amq.direct//controllerqueue