summaryrefslogtreecommitdiff
path: root/java/perftests/src
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2012-05-04 15:39:19 +0000
committerKim van der Riet <kpvdr@apache.org>2012-05-04 15:39:19 +0000
commit633c33f224f3196f3f9bd80bd2e418d8143fea06 (patch)
tree1391da89470593209466df68c0b40b89c14963b1 /java/perftests/src
parentc73f9286ebff93a6c8dbc29cf05e258c4b55c976 (diff)
downloadqpid-python-633c33f224f3196f3f9bd80bd2e418d8143fea06.tar.gz
QPID-3858: Updated branch - merged from trunk r.1333987
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1334037 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/perftests/src')
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java117
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java47
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java69
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java112
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java74
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java44
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java94
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java238
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java33
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java66
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java76
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java208
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java98
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java (renamed from java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java)13
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java251
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java212
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java31
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java136
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java45
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java100
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java174
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java68
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java27
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java122
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java179
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java27
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java46
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java47
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java129
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java79
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java96
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java46
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java (renamed from java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java)18
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java228
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java94
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java (renamed from java/perftests/src/main/java/org/apache/qpid/config/Connector.java)38
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java70
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java342
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java31
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java113
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java81
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java52
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java91
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java65
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java86
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java60
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java64
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java90
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java69
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java114
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java117
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java102
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java592
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java210
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java124
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java97
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java31
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java43
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java147
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java56
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java39
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java118
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java58
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java108
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java54
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java103
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java106
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java28
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java62
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java30
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java35
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java70
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java89
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java272
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java100
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java43
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java80
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java29
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java28
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java29
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java97
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java49
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java36
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java143
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java106
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java89
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java55
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java243
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java141
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java153
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java178
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java323
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java112
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java452
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java311
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java93
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java281
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java453
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java1818
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java251
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/topic/Config.java326
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/topic/Listener.java303
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java157
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java186
-rw-r--r--java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java344
-rw-r--r--java/perftests/src/main/resources/perftests.properties (renamed from java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties)8
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java96
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java48
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java92
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java108
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java159
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java180
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java107
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java183
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java55
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java183
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java83
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java219
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java88
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java73
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java76
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java153
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java30
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java99
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java198
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java144
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java253
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java111
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java113
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java56
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java56
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java94
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java79
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java78
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java51
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java89
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java93
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java113
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java102
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json72
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java40
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java183
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java162
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java61
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java272
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java152
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java144
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java89
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv2
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java72
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java116
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java28
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java186
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java156
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java90
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java323
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java119
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java132
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java249
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json63
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json41
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json55
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json77
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json107
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java157
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json17
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java95
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json65
-rw-r--r--java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties26
169 files changed, 15023 insertions, 6508 deletions
diff --git a/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java
deleted file mode 100644
index d94ca5592b..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.client.message;
-
-import javax.jms.JMSException;
-import javax.jms.Session;
-import javax.jms.ObjectMessage;
-import javax.jms.StreamMessage;
-import javax.jms.BytesMessage;
-import javax.jms.TextMessage;
-import javax.jms.DeliveryMode;
-import javax.jms.Destination;
-
-public class TestMessageFactory
-{
- private static final String MESSAGE_DATA_BYTES = "-message payload-message paylaod-message payload-message paylaod";
-
- public static TextMessage newTextMessage(Session session, int size) throws JMSException
- {
- return session.createTextMessage(createMessagePayload(size));
- }
-
- public static TextMessage newJMSTextMessage(Session session, int size, String encoding) throws JMSException
- {
-
- TextMessage message = session.createTextMessage();
- message.clearBody();
- message.setText(createMessagePayload(size));
- return message;
- }
-
- public static BytesMessage newBytesMessage(Session session, int size) throws JMSException
- {
- BytesMessage message = session.createBytesMessage();
- message.writeUTF(createMessagePayload(size));
- return message;
- }
-
- public static StreamMessage newStreamMessage(Session session, int size) throws JMSException
- {
- StreamMessage message = session.createStreamMessage();
- message.writeString(createMessagePayload(size));
- return message;
- }
-
- public static ObjectMessage newObjectMessage(Session session, int size) throws JMSException
- {
- if (size == 0)
- {
- return session.createObjectMessage();
- }
- else
- {
- return session.createObjectMessage(createMessagePayload(size));
- }
- }
-
- /**
- * Creates an ObjectMessage with given size and sets the JMS properties (JMSReplyTo and DeliveryMode)
- * @param session
- * @param replyDestination
- * @param size
- * @param persistent
- * @return the new ObjectMessage
- * @throws JMSException
- */
- public static ObjectMessage newObjectMessage(Session session, Destination replyDestination, int size, boolean persistent) throws JMSException
- {
- ObjectMessage msg = newObjectMessage(session, size);
-
- // Set the messages persistent delivery flag.
- msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
-
- // Ensure that the temporary reply queue is set as the reply to destination for the message.
- if (replyDestination != null)
- {
- msg.setJMSReplyTo(replyDestination);
- }
-
- return msg;
- }
-
- public static String createMessagePayload(int size)
- {
- StringBuffer buf = new StringBuffer(size);
- int count = 0;
- while (count <= (size - MESSAGE_DATA_BYTES.length()))
- {
- buf.append(MESSAGE_DATA_BYTES);
- count += MESSAGE_DATA_BYTES.length();
- }
- if (count < size)
- {
- buf.append(MESSAGE_DATA_BYTES, 0, size - count);
- }
-
- return buf.toString();
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java b/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java
deleted file mode 100644
index 76fd318625..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.config;
-
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.config.ConnectionFactoryInitialiser;
-import org.apache.qpid.config.ConnectorConfig;
-import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.url.URLSyntaxException;
-
-import javax.jms.ConnectionFactory;
-
-class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser
-{
- public ConnectionFactory getFactory(ConnectorConfig config)
- {
- try
- {
- final ConnectionURL connectionUrl = new AMQConnectionURL(ConnectionURL.AMQ_PROTOCOL +
- "://guest:guest@/test_path?brokerlist='tcp://" + config.getHost() + ":" + config.getPort() + "'");
- return new AMQConnectionFactory(connectionUrl);
- }
- catch (URLSyntaxException e)
- {
- throw new RuntimeException("Problem building URL", e);
- }
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java
deleted file mode 100644
index 14db74438f..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.config;
-
-public abstract class AbstractConfig
-{
- public boolean setOptions(String[] argv)
- {
- try
- {
- for(int i = 0; i < argv.length - 1; i += 2)
- {
- String key = argv[i];
- String value = argv[i+1];
- setOption(key, value);
- }
- return true;
- }
- catch(Exception e)
- {
- System.out.println(e.getMessage());
- }
- return false;
- }
-
- protected int parseInt(String msg, String i)
- {
- try
- {
- return Integer.parseInt(i);
- }
- catch(NumberFormatException e)
- {
- throw new RuntimeException(msg + ": " + i, e);
- }
- }
-
- protected long parseLong(String msg, String i)
- {
- try
- {
- return Long.parseLong(i);
- }
- catch(NumberFormatException e)
- {
- throw new RuntimeException(msg + ": " + i, e);
- }
- }
-
- public abstract void setOption(String key, String value);
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java
deleted file mode 100644
index a0248a8f79..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.config;
-
-import org.apache.qpid.config.ConnectionFactoryInitialiser;
-import org.apache.qpid.config.ConnectorConfig;
-import org.apache.qpid.client.JMSAMQException;
-
-import javax.jms.ConnectionFactory;
-import javax.jms.JMSException;
-import javax.management.MBeanServerConnection;
-import javax.management.ObjectName;
-import javax.management.MBeanException;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.naming.NameNotFoundException;
-import java.util.Hashtable;
-
-public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser
-{
- public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException
- {
- ConnectionFactory cf = null;
- InitialContext ic = null;
- Hashtable ht = new Hashtable();
- ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
- String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01");
- String jbossPort = System.getProperty("jboss.port", "1099");
- ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort);
- ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
-
- try
- {
- ic = new InitialContext(ht);
- if (!doesDestinationExist("topictest.messages", ic))
- {
- deployTopic("topictest.messages", ic);
- }
- if (!doesDestinationExist("topictest.control", ic))
- {
- deployTopic("topictest.control", ic);
- }
-
- cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
- return cf;
- }
- catch (NamingException e)
- {
- throw new JMSAMQException("Unable to lookup object: " + e, e);
- }
- catch (Exception e)
- {
- throw new JMSAMQException("Error creating topic: " + e, e);
- }
- }
-
- private boolean doesDestinationExist(String name, InitialContext ic) throws Exception
- {
- try
- {
- ic.lookup("/" + name);
- }
- catch (NameNotFoundException e)
- {
- return false;
- }
- return true;
- }
-
- private void deployTopic(String name, InitialContext ic) throws Exception
- {
- MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic);
-
- ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer");
-
- String jndiName = "/" + name;
- try
- {
- mBeanServer.invoke(serverObjectName, "createTopic",
- new Object[]{name, jndiName},
- new String[]{"java.lang.String", "java.lang.String"});
- }
- catch (MBeanException e)
- {
- System.err.println("Error: " + e);
- System.err.println("Cause: " + e.getCause());
- }
- }
-
- private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException
- {
- return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor");
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java b/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java
new file mode 100644
index 0000000000..9e865010f8
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java b/java/perftests/src/main/java/org/apache/qpid/disttest/ArgumentParser.java
new file mode 100644
index 0000000000..8c1f8675e3
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java b/java/perftests/src/main/java/org/apache/qpid/disttest/ClientRunner.java
new file mode 100644
index 0000000000..9c2f4a3d95
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java b/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java
new file mode 100644
index 0000000000..aa9c582bf8
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/ControllerRunner.java
@@ -0,0 +1,238 @@
+/*
+ * 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.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+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_DIR_PROP = "outputdir";
+
+ private static final String TEST_CONFIG_DEFAULT = "perftests-config.json";
+ private static final String DISTRIBUTED_DEFAULT = "false";
+ private static final String OUTPUT_DIR_DEFAULT = ".";
+
+ 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_DIR_PROP, OUTPUT_DIR_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 controller = new Controller(jmsDelegate, DistributedTestConstants.REGISTRATION_TIMEOUT, DistributedTestConstants.COMMAND_RESPONSE_TIMEOUT);
+
+ final List<String> testConfigFiles = getTestConfigFiles();
+ createClientsIfNotDistributed(testConfigFiles);
+
+ try
+ {
+ for (String testConfigFile : testConfigFiles)
+ {
+ final Config testConfig = buildTestConfigFrom(testConfigFile);
+ controller.setConfig(testConfig);
+
+ controller.awaitClientRegistrations();
+
+ LOGGER.info("Running test : " + testConfigFile);
+ runTest(controller, testConfigFile);
+ }
+ }
+ finally
+ {
+ controller.stopAllRegisteredClients();
+ }
+
+ }
+
+ private void runTest(Controller controller, String testConfigFile)
+ {
+ final Config testConfig = buildTestConfigFrom(testConfigFile);
+ controller.setConfig(testConfig);
+
+ ResultsForAllTests rawResultsForAllTests = controller.runAllTests();
+ ResultsForAllTests resultsForAllTests = _aggregator.aggregateResults(rawResultsForAllTests);
+
+ final String outputFile = generateOutputCsvNameFrom(testConfigFile);
+ writeResultsToFile(resultsForAllTests, outputFile);
+ }
+
+ private void createClientsIfNotDistributed(final List<String> testConfigFiles)
+ {
+ if(!isDistributed())
+ {
+ int maxNumberOfClients = 0;
+ for (String testConfigFile : testConfigFiles)
+ {
+ final Config testConfig = buildTestConfigFrom(testConfigFile);
+ final int numClients = testConfig.getTotalNumberOfClients();
+ maxNumberOfClients = Math.max(numClients, maxNumberOfClients);
+ }
+
+ //we must create the required test clients, running in single-jvm mode
+ for (int i = 1; i <= maxNumberOfClients; i++)
+ {
+ ClientRunner clientRunner = new ClientRunner();
+ clientRunner.setJndiPropertiesFileLocation(getJndiConfig());
+ clientRunner.runClients();
+ }
+ }
+ }
+
+ 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 generateOutputCsvNameFrom(String testConfigFile)
+ {
+ final String filenameOnlyWithExtension = new File(testConfigFile).getName();
+ final String cvsFile = filenameOnlyWithExtension.replaceFirst(".?\\w*$", ".csv");
+ final String outputDir = String.valueOf(getCliOptions().get(ControllerRunner.OUTPUT_DIR_PROP));
+
+ return new File(outputDir, cvsFile).getAbsolutePath();
+ }
+
+ private List<String> getTestConfigFiles()
+ {
+ final List<String> testConfigFile = new ArrayList<String>();
+ final File configFileOrDirectory = new File(getCliOptions().get(ControllerRunner.TEST_CONFIG_PROP));
+
+ if (configFileOrDirectory.isDirectory())
+ {
+ final String[] configFiles = configFileOrDirectory.list(new FilenameFilter()
+ {
+ @Override
+ public boolean accept(File dir, String name)
+ {
+ return new File(dir, name).isFile() && name.endsWith(".json");
+ }
+ });
+
+ for (String configFile : configFiles)
+ {
+ testConfigFile.add(new File(configFileOrDirectory, configFile).getAbsolutePath());
+ }
+ }
+ else
+ {
+ testConfigFile.add(configFileOrDirectory.getAbsolutePath());
+ }
+
+ return testConfigFile;
+ }
+
+ private Config buildTestConfigFrom(String testConfigFile)
+ {
+ ConfigReader configReader = new ConfigReader();
+ Config testConfig;
+ try
+ {
+ testConfig = configReader.getConfigFromFile(testConfigFile);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new DistributedTestException("Exception while loading test config from " + testConfigFile, e);
+ }
+ return testConfig;
+ }
+
+ private boolean isDistributed()
+ {
+ return Boolean.valueOf(getCliOptions().get(ControllerRunner.DISTRIBUTED_PROP));
+ }
+
+
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java b/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestConstants.java
new file mode 100644
index 0000000000..c4892edca9
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java b/java/perftests/src/main/java/org/apache/qpid/disttest/DistributedTestException.java
new file mode 100644
index 0000000000..d1d24dcfff
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java b/java/perftests/src/main/java/org/apache/qpid/disttest/Visitor.java
new file mode 100644
index 0000000000..52dad9aa4d
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java
new file mode 100644
index 0000000000..1d2d862301
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/Client.java
@@ -0,0 +1,208 @@
+/*
+ * 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)
+ {
+ if (LOGGER.isInfoEnabled())
+ {
+ LOGGER.info("Client " + getClientName() + " received 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/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientCommandVisitor.java
new file mode 100644
index 0000000000..791897323e
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java
index b120ed3f12..c88c0a6c86 100644
--- a/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ClientState.java
@@ -1,5 +1,4 @@
/*
- *
* 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
@@ -7,9 +6,9 @@
* 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
@@ -18,11 +17,9 @@
* under the License.
*
*/
-package org.apache.qpid.config;
+package org.apache.qpid.disttest.client;
-public interface ConnectorConfig
+public enum ClientState
{
- public String getHost();
- public int getPort();
- public String getFactory();
+ CREATED, READY, STOPPED, RUNNING_TEST;
}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java
new file mode 100644
index 0000000000..1b5e8276c2
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ConsumerParticipant.java
@@ -0,0 +1,251 @@
+/*
+ * 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();
+ final int acknowledgeMode = _jmsDelegate.getAcknowledgeMode(_command.getSessionName());
+
+ 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,
+ acknowledgeMode,
+ 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)
+ {
+ if (LOGGER.isTraceEnabled() && batchEnabled)
+ {
+ LOGGER.trace("Committing: batch size " + _command.getBatchSize() );
+ }
+ _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)
+ {
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("Committing: batch size " + _command.getBatchSize() );
+ }
+
+ // 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();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ConsumerParticipant [_command=" + _command + ", _startTime=" + _startTime + "]";
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/MessageProvider.java
new file mode 100644
index 0000000000..2dcf8940b6
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/Participant.java
new file mode 100644
index 0000000000..941ec90565
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java
new file mode 100644
index 0000000000..d5e307d50f
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutor.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.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
+ {
+ if (LOGGER.isInfoEnabled())
+ {
+ LOGGER.info("About to run participant " + _participant);
+ }
+ 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/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantExecutorRegistry.java
new file mode 100644
index 0000000000..3d9780e640
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.java
new file mode 100644
index 0000000000..7f6b96b87c
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ParticipantResultFactory.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.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 acknowledgeMode, int numberOfMessagesReceived, int payloadSize, long totalPayloadReceived, Date start, Date end)
+ {
+ ConsumerParticipantResult consumerParticipantResult = new ConsumerParticipantResult();
+
+ setTestProperties(consumerParticipantResult, command, participantName, clientRegisteredName, acknowledgeMode);
+ 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());
+ consumerParticipantResult.setTotalNumberOfConsumers(1);
+ consumerParticipantResult.setTotalNumberOfProducers(0);
+
+ return consumerParticipantResult;
+ }
+
+ public ProducerParticipantResult createForProducer(String participantName, String clientRegisteredName, CreateProducerCommand command, int acknowledgeMode, int numberOfMessagesSent, int payloadSize, long totalPayloadSent, Date start, Date end)
+ {
+ final ProducerParticipantResult producerParticipantResult = new ProducerParticipantResult();
+
+ producerParticipantResult.setStartDelay(command.getStartDelay());
+ producerParticipantResult.setDeliveryMode(command.getDeliveryMode());
+ producerParticipantResult.setPriority(command.getPriority());
+ producerParticipantResult.setInterval(command.getInterval());
+ producerParticipantResult.setTimeToLive(command.getTimeToLive());
+ producerParticipantResult.setTotalNumberOfConsumers(0);
+ producerParticipantResult.setTotalNumberOfProducers(1);
+
+
+ setTestProperties(producerParticipantResult, command, participantName, clientRegisteredName, acknowledgeMode);
+
+ setTestResultProperties(producerParticipantResult, numberOfMessagesSent, payloadSize, totalPayloadSent, start, end);
+
+ return producerParticipantResult;
+ }
+
+ 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, int acknowledgeMode)
+ {
+ participantResult.setParticipantName(participantName);
+ participantResult.setRegisteredClientName(clientRegisteredName);
+ participantResult.setBatchSize(command.getBatchSize());
+ participantResult.setMaximumDuration(command.getMaximumDuration());
+ participantResult.setAcknowledgeMode(acknowledgeMode);
+
+ }
+
+ 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/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java
new file mode 100644
index 0000000000..bcad81b4aa
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/client/ProducerParticipant.java
@@ -0,0 +1,174 @@
+/*
+ * 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");
+ }
+
+ int acknowledgeMode = _jmsDelegate.getAcknowledgeMode(_command.getSessionName());
+
+ 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)
+ {
+ if (LOGGER.isTraceEnabled() && _command.getBatchSize() > 0)
+ {
+ LOGGER.trace("Committing: batch size " + _command.getBatchSize() );
+ }
+ _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)
+ {
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("Committing: batch size " + _command.getBatchSize() );
+ }
+ _jmsDelegate.commitOrAcknowledgeMessage(lastPublishedMessage, _command.getSessionName());
+ }
+
+ Date start = new Date(startTime);
+ Date end = new Date();
+ int payloadSize = getPayloadSizeForResultIfConstantOrZeroOtherwise(allProducedPayloadSizes);
+
+ return _resultFactory.createForProducer(
+ getName(),
+ registeredClientName,
+ _command,
+ acknowledgeMode,
+ 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();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ProducerParticipant [command=" + _command + "]";
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertySupport.java
new file mode 100644
index 0000000000..a49ebf756e
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/GeneratedPropertyValue.java
new file mode 100644
index 0000000000..39c093fac5
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/ListPropertyValue.java
new file mode 100644
index 0000000000..4444351976
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/NumericGeneratedPropertySupport.java
new file mode 100644
index 0000000000..e0ae137c35
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValue.java
new file mode 100644
index 0000000000..97adc0cee1
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/PropertyValueFactory.java
new file mode 100644
index 0000000000..fa44b2da1e
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RandomPropertyValue.java
new file mode 100644
index 0000000000..4f44a4bca8
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/RangePropertyValue.java
new file mode 100644
index 0000000000..3aca4d4bca
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/client/property/SimplePropertyValue.java
new file mode 100644
index 0000000000..9141e68656
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.java
new file mode 100644
index 0000000000..eaccb54f0e
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ClientRegistry.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.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>();
+
+ private final Object _lock = new Object();
+
+ public void registerClient(String clientName)
+ {
+ final boolean alreadyContainsClient = !_registeredClientNames.add(clientName);
+ if (alreadyContainsClient)
+ {
+ throw new DistributedTestException("Duplicate client name " + clientName);
+ }
+
+ notifyAllWaiters();
+
+ if (LOGGER.isInfoEnabled())
+ {
+ LOGGER.info("Client registered: " + clientName);
+ }
+ }
+
+
+ public Collection<String> getClients()
+ {
+ return Collections.unmodifiableSet(_registeredClientNames);
+ }
+
+ public int awaitClients(int numberOfClientsToAwait, long timeout)
+ {
+ final long endTime = System.currentTimeMillis() + timeout;
+
+ int numberOfClientsAbsent = numberOfClientsToAwait - _registeredClientNames.size();
+ long remainingTimeout = endTime - System.currentTimeMillis();
+
+ while(numberOfClientsAbsent > 0 && remainingTimeout > 0)
+ {
+ synchronized (_lock)
+ {
+ try
+ {
+ _lock.wait(remainingTimeout);
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ numberOfClientsAbsent = numberOfClientsToAwait - _registeredClientNames.size();
+ remainingTimeout = endTime - System.currentTimeMillis();
+ }
+
+ return numberOfClientsAbsent < 0 ? 0 : numberOfClientsAbsent;
+ }
+
+ private void notifyAllWaiters()
+ {
+ synchronized (_lock)
+ {
+ _lock.notifyAll();
+ }
+ }
+
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandForClient.java
new file mode 100644
index 0000000000..6c0c253807
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java
index a9984eb09a..e2f40bebe8 100644
--- a/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/CommandListener.java
@@ -1,5 +1,4 @@
/*
- *
* 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
@@ -7,9 +6,9 @@
* 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
@@ -18,12 +17,15 @@
* under the License.
*
*/
-package org.apache.qpid.config;
+package org.apache.qpid.disttest.controller;
-import javax.jms.ConnectionFactory;
-import javax.jms.JMSException;
+import org.apache.qpid.disttest.message.Command;
-public interface ConnectionFactoryInitialiser
+public interface CommandListener
{
- public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException;
+
+ public abstract void processCommand(Command command);
+
+ public boolean supports(Command command);
+
}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java
new file mode 100644
index 0000000000..7c935065f0
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/Controller.java
@@ -0,0 +1,228 @@
+/*
+ * 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 _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();
+
+ _jmsDelegate.addCommandListener(new RegisterClientCommandListener());
+ _jmsDelegate.addCommandListener(new StopClientResponseListener());
+ _jmsDelegate.start();
+ }
+
+ public void setConfig(Config config)
+ {
+ _config = config;
+ validateConfiguration();
+ }
+
+ public void awaitClientRegistrations()
+ {
+ LOGGER.info("Awaiting client registrations");
+
+ final int numberOfAbsentClients = _clientRegistry.awaitClients(_config.getTotalNumberOfClients(), _registrationTimeout);
+ if (numberOfAbsentClients > 0)
+ {
+ String formattedMessage = String.format("Timed out waiting for registrations. Expecting %d more registrations", numberOfAbsentClients);
+ throw new DistributedTestException(formattedMessage);
+ }
+
+ }
+
+ 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();
+
+ _jmsDelegate.registerClient(registrationCommand);
+ _clientRegistry.registerClient(clientName);
+ }
+
+ void processStopClientResponse(final Response response)
+ {
+ // TODO clientRegistry should expose a deregisterClient
+ _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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ParticipatingClients.java
new file mode 100644
index 0000000000..077d628697
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/config/Connector.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java
index 81541a3260..6c5ff3450c 100644
--- a/java/perftests/src/main/java/org/apache/qpid/config/Connector.java
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/ResultsForAllTests.java
@@ -1,5 +1,4 @@
/*
- *
* 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
@@ -7,37 +6,44 @@
* 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.config;
+package org.apache.qpid.disttest.controller;
+
+import java.util.ArrayList;
+import java.util.List;
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
+import org.apache.qpid.disttest.results.aggregation.ITestResult;
-public class Connector
+public class ResultsForAllTests
{
- public Connection createConnection(ConnectorConfig config) throws Exception
+ private List<ITestResult> _results = new ArrayList<ITestResult>();
+ private boolean _hasErrors;
+
+ public List<ITestResult> getTestResults()
{
- return getConnectionFactory(config).createConnection();
+ return _results;
}
- ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception
+ public void add(ITestResult testResult)
{
- String factory = config.getFactory();
- if(factory == null)
+ _results.add(testResult);
+ if(testResult.hasErrors())
{
- factory = AMQConnectionFactoryInitialiser.class.getName();
+ _hasErrors = true;
}
- System.out.println("Using " + factory);
- return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config);
+ }
+
+ public boolean hasErrors()
+ {
+ return _hasErrors;
}
}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestResult.java
new file mode 100644
index 0000000000..756c641532
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java
new file mode 100644
index 0000000000..30595269b3
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunner.java
@@ -0,0 +1,342 @@
+/*
+ * 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;
+
+ private Thread _removeQueuesShutdownHook = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ LOGGER.info("Shutdown intercepted: deleting test queues");
+ try
+ {
+ deleteQueues();
+ }
+ catch (Throwable t)
+ {
+ LOGGER.error("Failed to delete test queues during shutdown", t);
+ }
+ }
+ };
+
+ 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;
+ Runtime.getRuntime().addShutdownHook(_removeQueuesShutdownHook);
+
+ sendTestSetupCommands();
+ awaitCommandResponses();
+ sendCommandToParticipatingClients(new StartTestCommand());
+ awaitCommandResponses();
+
+ awaitTestResults();
+
+ sendCommandToParticipatingClients(new TearDownTestCommand());
+ awaitCommandResponses();
+ }
+ finally
+ {
+
+ if (queuesCreated)
+ {
+ deleteQueues();
+ }
+
+ Runtime.getRuntime().removeShutdownHook(_removeQueuesShutdownHook);
+
+ }
+ }
+
+ void createQueues()
+ {
+ List<QueueConfig> queues = _testInstance.getQueues();
+ if (!queues.isEmpty())
+ {
+ _jmsDelegate.createQueues(queues);
+ }
+ }
+
+ void sendTestSetupCommands()
+ {
+ List<CommandForClient> commandsForAllClients = _testInstance.createCommands();
+ final int numberOfCommandsToSend = commandsForAllClients.size();
+ _commandResponseLatch = new CountDownLatch(numberOfCommandsToSend);
+
+ LOGGER.debug("About to send {} command(s)", numberOfCommandsToSend);
+
+ for (CommandForClient commandForClient : commandsForAllClients)
+ {
+ String configuredClientName = commandForClient.getClientName();
+ String registeredClientName = _participatingClients.getRegisteredNameFromConfiguredName(configuredClientName);
+
+ Command command = commandForClient.getCommand();
+
+ LOGGER.debug("Sending command : {} ", command);
+
+ 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();
+ final int numberOfClients = participatingRegisteredClients.size();
+ _commandResponseLatch = new CountDownLatch(numberOfClients);
+
+ LOGGER.debug("About to send command {} to {} clients", command, numberOfClients);
+
+ for (final String clientName : participatingRegisteredClients)
+ {
+ LOGGER.debug("Sending command : {} ", command);
+ 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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/TestRunnerFactory.java
new file mode 100644
index 0000000000..bf0e5afb9c
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ClientConfig.java
new file mode 100644
index 0000000000..4353a85cd3
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/Config.java
new file mode 100644
index 0000000000..fe56137276
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConfigReader.java
new file mode 100644
index 0000000000..6288b42eac
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConnectionConfig.java
new file mode 100644
index 0000000000..e2cc31e21e
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ConsumerConfig.java
new file mode 100644
index 0000000000..ed47e02667
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/IterationValue.java
new file mode 100644
index 0000000000..ef953a5d07
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/MessageProviderConfig.java
new file mode 100644
index 0000000000..318ec7f045
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ParticipantConfig.java
new file mode 100644
index 0000000000..31037a3038
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/ProducerConfig.java
new file mode 100644
index 0000000000..7806528a8c
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/QueueConfig.java
new file mode 100644
index 0000000000..cffc2b7c50
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/SessionConfig.java
new file mode 100644
index 0000000000..12372e5391
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestConfig.java
new file mode 100644
index 0000000000..2bb5f1b289
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java b/java/perftests/src/main/java/org/apache/qpid/disttest/controller/config/TestInstance.java
new file mode 100644
index 0000000000..9f555ef4da
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java
new file mode 100644
index 0000000000..d68fc86a0e
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ClientJmsDelegate.java
@@ -0,0 +1,592 @@
+/*
+ * 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());
+ LOGGER.info("Created session " + command.getSessionName() + " with transacted = " + newSession.getTransacted() + " and acknowledgeMode = " + newSession.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 int getAcknowledgeMode(final String sessionName)
+ {
+ try
+ {
+ final Session session = _testSessions.get(sessionName);
+ return session.getAcknowledgeMode();
+ }
+ catch (final JMSException jmse)
+ {
+ throw new DistributedTestException("Unable to determine acknowledgement mode for 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/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/ControllerJmsDelegate.java
new file mode 100644
index 0000000000..69da409be5
--- /dev/null
+++ b/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(_session, queues);
+ }
+
+ public void deleteQueues(List<QueueConfig> queues)
+ {
+ _queueCreator.deleteQueues(_session, queues);
+ }
+
+ public void addCommandListener(CommandListener commandListener)
+ {
+ _commandListeners.add(commandListener);
+ }
+
+ public void removeCommandListener(CommandListener commandListener)
+ {
+ _commandListeners.remove(commandListener);
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/JmsMessageAdaptor.java
new file mode 100644
index 0000000000..c9dba21a74
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.java
new file mode 100644
index 0000000000..912ce54495
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QpidQueueCreator.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.jms;
+
+import java.util.List;
+
+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(Session session, List<QueueConfig> configs)
+ {
+ AMQSession<?, ?> amqSession = (AMQSession<?, ?>)session;
+ for (QueueConfig queueConfig : configs)
+ {
+ createQueue(amqSession, queueConfig);
+ }
+ }
+
+ @Override
+ public void deleteQueues(Session session, List<QueueConfig> configs)
+ {
+ AMQSession<?, ?> amqSession = (AMQSession<?, ?>)session;
+ for (QueueConfig queueConfig : configs)
+ {
+ deleteQueue(amqSession, 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);
+ }
+ }
+
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/jms/QueueCreator.java
new file mode 100644
index 0000000000..0947dd53cb
--- /dev/null
+++ b/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.Session;
+
+import org.apache.qpid.disttest.controller.config.QueueConfig;
+
+public interface QueueCreator
+{
+ public void createQueues(final Session session, final List<QueueConfig> configs);
+ public void deleteQueues(final Session session, final List<QueueConfig> configs);
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java b/java/perftests/src/main/java/org/apache/qpid/disttest/json/JsonHandler.java
new file mode 100644
index 0000000000..8e50cd4f11
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java b/java/perftests/src/main/java/org/apache/qpid/disttest/json/PropertyValueAdapter.java
new file mode 100644
index 0000000000..94f712e652
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/Command.java
new file mode 100644
index 0000000000..86b4d0e439
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CommandType.java
new file mode 100644
index 0000000000..b04cbdaba1
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ConsumerParticipantResult.java
new file mode 100644
index 0000000000..f92e3ea538
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConnectionCommand.java
new file mode 100644
index 0000000000..c5a96e9a94
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateConsumerCommand.java
new file mode 100644
index 0000000000..678e428f94
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateMessageProviderCommand.java
new file mode 100644
index 0000000000..3f30fdd96a
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java
new file mode 100644
index 0000000000..b1caa6ef75
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateParticpantCommand.java
@@ -0,0 +1,103 @@
+/*
+ * 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.ToStringBuilder;
+
+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;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this);
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateProducerCommand.java
new file mode 100644
index 0000000000..69dfe1ff5a
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateResponderCommand.java
new file mode 100644
index 0000000000..85a2b5e548
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/CreateSessionCommand.java
new file mode 100644
index 0000000000..f6f59c26af
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/NoOpCommand.java
new file mode 100644
index 0000000000..1cdaf00163
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/OutputAttribute.java
new file mode 100644
index 0000000000..b912eaa1cb
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.java
new file mode 100644
index 0000000000..ccc7c0d9fb
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttribute.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.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("testName"),
+ ITERATION_NUMBER("iterationNumber"),
+ CONFIGURED_CLIENT_NAME("clientName"),
+ PARTICIPANT_NAME("participantName"),
+ NUMBER_OF_MESSAGES_PROCESSED("numberOfMessages"),
+ PAYLOAD_SIZE("payloadSizeB"),
+ PRIORITY("priority"),
+ TIME_TO_LIVE("timeToLiveMs"),
+ ACKNOWLEDGE_MODE("acknowledgeMode"),
+ DELIVERY_MODE("deliveryMode"),
+ BATCH_SIZE("batchSize"),
+ MAXIMUM_DURATION("maximumDurationMs"),
+ PRODUCER_START_DELAY("producerStartDelayMs"),
+ PRODUCER_INTERVAL("producerIntervalMs"),
+ IS_TOPIC("isTopic"),
+ IS_DURABLE_SUBSCRIPTION("isDurableSubscription"),
+ IS_BROWSIING_SUBSCRIPTION("isBrowsingSubscription"),
+ IS_SELECTOR("isSelector"),
+ IS_NO_LOCAL("isNoLocal"),
+ IS_SYNCHRONOUS_CONSUMER("isSynchronousConsumer"),
+ TOTAL_NUMBER_OF_CONSUMERS("totalNumberOfConsumers"),
+ TOTAL_NUMBER_OF_PRODUCERS("totalNumberOfProducers"),
+ TOTAL_PAYLOAD_PROCESSED("totalPayloadProcessedB"),
+ THROUGHPUT("throughputKbPerS"),
+ TIME_TAKEN("timeTakenMs"),
+ ERROR_MESSAGE("errorMessage");
+
+ private String _displayName;
+
+ ParticipantAttribute(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantAttributeExtractor.java
new file mode 100644
index 0000000000..95a19ceefc
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java
new file mode 100644
index 0000000000..a6d3d91bae
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ParticipantResult.java
@@ -0,0 +1,272 @@
+/*
+ * 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 int _iterationNumber;
+
+ private long _startInMillis;
+ private long _endInMillis;
+ private int _batchSize;
+ private long _maximumDuration;
+
+ private String _configuredClientName;
+
+ private long _numberOfMessagesProcessed;
+ private long _totalPayloadProcessed;
+ private int _payloadSize;
+ private double _throughput;
+
+ private int _totalNumberOfConsumers;
+ private int _totalNumberOfProducers;
+
+ // As Session.SESSION_TRANSACTED is 0, we use value -1 so we can distinguish the case where an aggregated result
+ // summarizes results from participants using different session acknowledge modes.
+ private int _acknowledgeMode = -1;
+
+ 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;
+ }
+
+ public void setTotalNumberOfConsumers(int totalNumberOfConsumers)
+ {
+ _totalNumberOfConsumers = totalNumberOfConsumers;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.TOTAL_NUMBER_OF_CONSUMERS)
+ public int getTotalNumberOfConsumers()
+ {
+ return _totalNumberOfConsumers;
+ }
+
+ public void setTotalNumberOfProducers(int totalNumberOfProducers)
+ {
+ _totalNumberOfProducers = totalNumberOfProducers;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.TOTAL_NUMBER_OF_PRODUCERS)
+ public int getTotalNumberOfProducers()
+ {
+ return _totalNumberOfProducers;
+ }
+
+ @OutputAttribute(attribute=ParticipantAttribute.ACKNOWLEDGE_MODE)
+ public int getAcknowledgeMode()
+ {
+ return _acknowledgeMode;
+ }
+
+ public void setAcknowledgeMode(int acknowledgeMode)
+ {
+ _acknowledgeMode = acknowledgeMode;
+ }
+
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/ProducerParticipantResult.java
new file mode 100644
index 0000000000..766c90eec8
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/RegisterClientCommand.java
new file mode 100644
index 0000000000..af880a37d9
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/Response.java
new file mode 100644
index 0000000000..aac056efcb
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/StartTestCommand.java
new file mode 100644
index 0000000000..4a53697ecd
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/StopClientCommand.java
new file mode 100644
index 0000000000..08758aaa69
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java b/java/perftests/src/main/java/org/apache/qpid/disttest/message/TearDownTestCommand.java
new file mode 100644
index 0000000000..6b1367d4f9
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/AggregatedTestResult.java
new file mode 100644
index 0000000000..5e6da2e65b
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/Aggregator.java
new file mode 100644
index 0000000000..cde30d36e5
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ITestResult.java
new file mode 100644
index 0000000000..3f9cdff69d
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java
new file mode 100644
index 0000000000..207d0131eb
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregator.java
@@ -0,0 +1,143 @@
+/*
+ * 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 int _totalNumberOfConsumers = 0;
+ private int _totalNumberOfProducers = 0;
+
+ private NavigableSet<Integer> _encounteredPayloadSizes = new TreeSet<Integer>();
+ private NavigableSet<Integer> _encounteredIterationNumbers = new TreeSet<Integer>();
+ private NavigableSet<Integer> _encounteredBatchSizes = new TreeSet<Integer>();
+ private NavigableSet<Integer> _encounteredAcknowledgeMode = new TreeSet<Integer>();
+ private NavigableSet<String> _encountedTestNames = new TreeSet<String>();
+
+ public ParticipantResultAggregator(Class<? extends ParticipantResult> targetClass, String aggregateResultName)
+ {
+ _aggregatedResultName = aggregateResultName;
+ _targetClass = targetClass;
+ }
+
+ 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();
+ _totalNumberOfConsumers += result.getTotalNumberOfConsumers();
+ _totalNumberOfProducers += result.getTotalNumberOfProducers();
+ _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());
+ _encounteredBatchSizes.add(result.getBatchSize());
+ _encounteredAcknowledgeMode.add(result.getAcknowledgeMode());
+ }
+
+ private void setComputedVariableAttributes(ParticipantResult aggregatedResult)
+ {
+ aggregatedResult.setNumberOfMessagesProcessed(_numberOfMessagesProcessed);
+ aggregatedResult.setTotalPayloadProcessed(_totalPayloadProcessed);
+ aggregatedResult.setTotalNumberOfConsumers(_totalNumberOfConsumers);
+ aggregatedResult.setTotalNumberOfProducers(_totalNumberOfProducers);
+ 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());
+ }
+ if (_encounteredBatchSizes.size() == 1)
+ {
+ aggregatedResult.setBatchSize(_encounteredBatchSizes.first());
+ }
+ if (_encounteredAcknowledgeMode.size() == 1)
+ {
+ aggregatedResult.setAcknowledgeMode(_encounteredAcknowledgeMode.first());
+ }
+ }
+
+ private double calculateThroughputInKiloBytesPerSecond()
+ {
+ double durationInMillis = _maxEndDate - _minStartDate;
+ double durationInSeconds = durationInMillis / 1000;
+ double totalPayloadProcessedInKiloBytes = ((double)_totalPayloadProcessed) / 1024;
+
+ return totalPayloadProcessedInKiloBytes/durationInSeconds;
+ }
+
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.java
new file mode 100644
index 0000000000..5934e0e997
--- /dev/null
+++ b/java/perftests/src/main/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregator.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.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)
+ {
+ ParticipantResultAggregator consumerResultAggregator = new ParticipantResultAggregator(ConsumerParticipantResult.class,
+ ALL_CONSUMER_PARTICIPANTS_NAME);
+ ParticipantResultAggregator producerResultAggregator = new ParticipantResultAggregator(ProducerParticipantResult.class,
+ ALL_PRODUCER_PARTICIPANTS_NAME);
+ ParticipantResultAggregator aggregatedResultsAggregator = new ParticipantResultAggregator(ParticipantResult.class,
+ ALL_PARTICIPANTS_NAME);
+
+ boolean hasError = aggregateOriginalResults(originalTestResult,
+ consumerResultAggregator,
+ producerResultAggregator);
+
+ ParticipantResult aggregatedProducerResult = producerResultAggregator.getAggregatedResult();
+ ParticipantResult aggregaredConsumerResult = consumerResultAggregator.getAggregatedResult();
+
+ ParticipantResult aggregatedAllResult = aggregateAggregatedResults(
+ aggregatedResultsAggregator, aggregatedProducerResult,
+ aggregaredConsumerResult);
+
+ applyNonAggregateablesToAll(aggregatedAllResult,
+ aggregatedProducerResult, aggregaredConsumerResult);
+
+ AggregatedTestResult newTestResult = new AggregatedTestResult(originalTestResult);
+ newTestResult.setAllProducerParticipantResult(aggregatedProducerResult);
+ newTestResult.setAllConsumerParticipantResult(aggregaredConsumerResult);
+ newTestResult.setAllParticipantResult(aggregatedAllResult);
+
+ if (hasError)
+ {
+ aggregatedAllResult.setErrorMessage(TestResultAggregator.AGGREGATED_ERROR_MESSAGE);
+ }
+
+ return newTestResult;
+ }
+
+ private ParticipantResult aggregateAggregatedResults(
+ ParticipantResultAggregator aggregatedResultsAggregator,
+ ParticipantResult aggregatedProducerResult,
+ ParticipantResult aggregaredConsumerResult)
+ {
+ aggregatedResultsAggregator.aggregate(aggregatedProducerResult);
+ aggregatedResultsAggregator.aggregate(aggregaredConsumerResult);
+ ParticipantResult aggregatedAllResult = aggregatedResultsAggregator.getAggregatedResult();
+ return aggregatedAllResult;
+ }
+
+ private boolean aggregateOriginalResults(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 void applyNonAggregateablesToAll(ParticipantResult aggregatedAllResult, ParticipantResult aggregatedProducerResult, ParticipantResult aggregatedConsumerResult)
+ {
+ aggregatedAllResult.setStartDate(aggregatedProducerResult.getStartDate());
+ aggregatedAllResult.setEndDate(aggregatedConsumerResult.getEndDate());
+
+ aggregatedAllResult.setNumberOfMessagesProcessed(aggregatedConsumerResult.getNumberOfMessagesProcessed());
+ aggregatedAllResult.setTotalPayloadProcessed(aggregatedConsumerResult.getTotalPayloadProcessed());
+ aggregatedAllResult.setThroughput(aggregatedConsumerResult.getThroughput());
+ }
+}
diff --git a/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVFormater.java
new file mode 100644
index 0000000000..52e53ca624
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java b/java/perftests/src/main/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparator.java
new file mode 100644
index 0000000000..0e1fbbc3c6
--- /dev/null
+++ b/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/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java b/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java
deleted file mode 100644
index 5b6169ed2d..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.oldtopic;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.config.ConnectorConfig;
-import org.apache.qpid.config.ConnectionFactoryInitialiser;
-import org.apache.qpid.config.Connector;
-import org.apache.qpid.config.AbstractConfig;
-
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-
-class Config extends AbstractConfig implements ConnectorConfig
-{
-
- private String host = "localhost";
- private int port = 5672;
- private String factory = null;
-
- private int payload = 256;
- private int messages = 1000;
- private int clients = 1;
- private int batch = 1;
- private long delay = 1;
- private int warmup;
- private int ackMode= AMQSession.NO_ACKNOWLEDGE;
- private String clientId;
- private String subscriptionId;
- private boolean persistent;
-
- public Config()
- {
- }
-
- int getAckMode()
- {
- return ackMode;
- }
-
- void setPayload(int payload)
- {
- this.payload = payload;
- }
-
- int getPayload()
- {
- return payload;
- }
-
- void setClients(int clients)
- {
- this.clients = clients;
- }
-
- int getClients()
- {
- return clients;
- }
-
- void setMessages(int messages)
- {
- this.messages = messages;
- }
-
- int getMessages()
- {
- return messages;
- }
-
- public String getHost()
- {
- return host;
- }
-
- public void setHost(String host)
- {
- this.host = host;
- }
-
- public int getPort()
- {
- return port;
- }
-
- public String getFactory()
- {
- return factory;
- }
-
- public void setPort(int port)
- {
- this.port = port;
- }
-
- int getBatch()
- {
- return batch;
- }
-
- void setBatch(int batch)
- {
- this.batch = batch;
- }
-
- int getWarmup()
- {
- return warmup;
- }
-
- void setWarmup(int warmup)
- {
- this.warmup = warmup;
- }
-
- public long getDelay()
- {
- return delay;
- }
-
- public void setDelay(long delay)
- {
- this.delay = delay;
- }
-
- String getClientId()
- {
- return clientId;
- }
-
- String getSubscriptionId()
- {
- return subscriptionId;
- }
-
- boolean usePersistentMessages()
- {
- return persistent;
- }
-
- public void setOption(String key, String value)
- {
- if("-host".equalsIgnoreCase(key))
- {
- setHost(value);
- }
- else if("-port".equalsIgnoreCase(key))
- {
- try
- {
- setPort(Integer.parseInt(value));
- }
- catch(NumberFormatException e)
- {
- throw new RuntimeException("Bad port number: " + value);
- }
- }
- else if("-payload".equalsIgnoreCase(key))
- {
- setPayload(parseInt("Bad payload size", value));
- }
- else if("-messages".equalsIgnoreCase(key))
- {
- setMessages(parseInt("Bad message count", value));
- }
- else if("-clients".equalsIgnoreCase(key))
- {
- setClients(parseInt("Bad client count", value));
- }
- else if("-batch".equalsIgnoreCase(key))
- {
- setBatch(parseInt("Bad batch count", value));
- }
- else if("-delay".equalsIgnoreCase(key))
- {
- setDelay(parseLong("Bad batch delay", value));
- }
- else if("-warmup".equalsIgnoreCase(key))
- {
- setWarmup(parseInt("Bad warmup count", value));
- }
- else if("-ack".equalsIgnoreCase(key))
- {
- ackMode = parseInt("Bad ack mode", value);
- }
- else if("-factory".equalsIgnoreCase(key))
- {
- factory = value;
- }
- else if("-clientId".equalsIgnoreCase(key))
- {
- clientId = value;
- }
- else if("-subscriptionId".equalsIgnoreCase(key))
- {
- subscriptionId = value;
- }
- else if("-persistent".equalsIgnoreCase(key))
- {
- persistent = "true".equalsIgnoreCase(value);
- }
- else
- {
- System.out.println("Ignoring unrecognised option: " + key);
- }
- }
-
- static String getAckModeDescription(int ackMode)
- {
- switch(ackMode)
- {
- case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE";
- case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE";
- case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE";
- case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE";
- case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE";
- }
- return "AckMode=" + ackMode;
- }
-
- public Connection createConnection() throws Exception
- {
- return new Connector().createConnection(this);
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java b/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java
deleted file mode 100644
index 4732782d4c..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.oldtopic;
-import org.apache.log4j.*;
-import javax.jms.Connection;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-
-public class Listener implements MessageListener
-{
- private final Connection _connection;
- private final MessageProducer _controller;
- private final javax.jms.Session _session;
- private final MessageFactory _factory;
- private boolean init;
- private int count;
- private long start;
-
- Listener(Connection connection, int ackMode) throws Exception
- {
- this(connection, ackMode, null);
- }
-
- Listener(Connection connection, int ackMode, String name) throws Exception
- {
- _connection = connection;
- _session = connection.createSession(false, ackMode);
- _factory = new MessageFactory(_session);
-
- //register for events
- if(name == null)
- {
- _factory.createTopicConsumer().setMessageListener(this);
- }
- else
- {
- _factory.createDurableTopicConsumer(name).setMessageListener(this);
- }
-
- _connection.start();
-
- _controller = _factory.createControlPublisher();
- System.out.println("Waiting for messages " +
- Config.getAckModeDescription(ackMode)
- + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")")
- + "...");
-
- }
-
- private void shutdown()
- {
- try
- {
- _session.close();
- _connection.stop();
- _connection.close();
- }
- catch(Exception e)
- {
- e.printStackTrace(System.out);
- }
- }
-
- private void report()
- {
- try
- {
- String msg = getReport();
- _controller.send(_factory.createReportResponseMessage(msg));
- System.out.println("Sent report: " + msg);
- }
- catch(Exception e)
- {
- e.printStackTrace(System.out);
- }
- }
-
- private String getReport()
- {
- long time = (System.currentTimeMillis() - start);
- return "Received " + count + " in " + time + "ms";
- }
-
- public void onMessage(Message message)
- {
- if(!init)
- {
- start = System.currentTimeMillis();
- count = 0;
- init = true;
- }
-
- if(_factory.isShutdown(message))
- {
- shutdown();
- }
- else if(_factory.isReport(message))
- {
- //send a report:
- report();
- init = false;
- }
- else if (++count % 100 == 0)
- {
- System.out.println("Received " + count + " messages.");
- }
- }
-
- public static void main(String[] argv) throws Exception
- {
- Config config = new Config();
- config.setOptions(argv);
-
- Connection con = config.createConnection();
- if(config.getClientId() != null)
- {
- con.setClientID(config.getClientId());
- }
- new Listener(con, config.getAckMode(), config.getSubscriptionId());
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java b/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java
deleted file mode 100644
index b2fbeb7e35..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.oldtopic;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQTopic;
-
-import javax.jms.*;
-
-/**
- */
-class MessageFactory
-{
- private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray();
-
- private final Session _session;
- private final Topic _topic;
- private final Topic _control;
- private final byte[] _payload;
-
-
- MessageFactory(Session session) throws JMSException
- {
- this(session, 256);
- }
-
- MessageFactory(Session session, int size) throws JMSException
- {
- _session = session;
-/* if(session instanceof AMQSession)
- {
- _topic = new AMQTopic("topictest.messages");
- _control = new AMQTopic("topictest.control");
- }
- else*/
- {
- _topic = session.createTopic("topictest.messages");
- _control = session.createTopic("topictest.control");
- }
- _payload = new byte[size];
-
- for(int i = 0; i < size; i++)
- {
- _payload[i] = (byte) DATA[i % DATA.length];
- }
- }
-
- Topic getTopic()
- {
- return _topic;
- }
-
- Message createEventMessage() throws JMSException
- {
- BytesMessage msg = _session.createBytesMessage();
- msg.writeBytes(_payload);
- return msg;
- }
-
- Message createShutdownMessage() throws JMSException
- {
- return _session.createTextMessage("SHUTDOWN");
- }
-
- Message createReportRequestMessage() throws JMSException
- {
- return _session.createTextMessage("REPORT");
- }
-
- Message createReportResponseMessage(String msg) throws JMSException
- {
- return _session.createTextMessage(msg);
- }
-
- boolean isShutdown(Message m)
- {
- return checkText(m, "SHUTDOWN");
- }
-
- boolean isReport(Message m)
- {
- return checkText(m, "REPORT");
- }
-
- Object getReport(Message m)
- {
- try
- {
- return ((TextMessage) m).getText();
- }
- catch (JMSException e)
- {
- e.printStackTrace(System.out);
- return e.toString();
- }
- }
-
- MessageConsumer createTopicConsumer() throws Exception
- {
- return _session.createConsumer(_topic);
- }
-
- MessageConsumer createDurableTopicConsumer(String name) throws Exception
- {
- return _session.createDurableSubscriber(_topic, name);
- }
-
- MessageConsumer createControlConsumer() throws Exception
- {
- return _session.createConsumer(_control);
- }
-
- MessageProducer createTopicPublisher() throws Exception
- {
- return _session.createProducer(_topic);
- }
-
- MessageProducer createControlPublisher() throws Exception
- {
- return _session.createProducer(_control);
- }
-
- private static boolean checkText(Message m, String s)
- {
- try
- {
- return m instanceof TextMessage && ((TextMessage) m).getText().equals(s);
- }
- catch (JMSException e)
- {
- e.printStackTrace(System.out);
- return false;
- }
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java b/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java
deleted file mode 100644
index 841fcc63ad..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.oldtopic;
-
-import javax.jms.*;
-
-public class Publisher implements MessageListener
-{
- private final Object _lock = new Object();
- private final Connection _connection;
- private final Session _session;
- private final MessageFactory _factory;
- private final MessageProducer _publisher;
- private int _count;
-
- Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception
- {
- _connection = connection;
- _session = _connection.createSession(false, ackMode);
- _factory = new MessageFactory(_session, size);
- _publisher = _factory.createTopicPublisher();
- _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
- System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + ".");
- }
-
- private void test(Config config) throws Exception
- {
- test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup());
- }
-
- private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception
- {
- _factory.createControlConsumer().setMessageListener(this);
- _connection.start();
-
- if(warmup > 0)
- {
- System.out.println("Runing warmup (" + warmup + " msgs)");
- long time = batch(warmup, consumerCount);
- System.out.println("Warmup completed in " + time + "ms");
- }
-
- long[] times = new long[batches];
- for(int i = 0; i < batches; i++)
- {
- if(i > 0)
- {
- Thread.sleep(delay*1000);
- }
- times[i] = batch(msgCount, consumerCount);
- System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms.");
- }
-
- long min = min(times);
- long max = max(times);
- System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max));
-
- //request shutdown
- _publisher.send(_factory.createShutdownMessage());
-
- _connection.stop();
- _connection.close();
- }
-
- private long batch(int msgCount, int consumerCount) throws Exception
- {
- _count = consumerCount;
- long start = System.currentTimeMillis();
- publish(msgCount);
- waitForCompletion(consumerCount);
- return System.currentTimeMillis() - start;
- }
-
- private void publish(int count) throws Exception
- {
-
- //send events
- for (int i = 0; i < count; i++)
- {
- _publisher.send(_factory.createEventMessage());
- if ((i + 1) % 100 == 0)
- {
- System.out.println("Sent " + (i + 1) + " messages");
- }
- }
-
- //request report
- _publisher.send(_factory.createReportRequestMessage());
- }
-
- private void waitForCompletion(int consumers) throws Exception
- {
- System.out.println("Waiting for completion...");
- synchronized (_lock)
- {
- while (_count > 0)
- {
- _lock.wait();
- }
- }
- }
-
-
- public void onMessage(Message message)
- {
- System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining");
- if (_count == 0)
- {
- synchronized (_lock)
- {
- _lock.notify();
- }
- }
- }
-
- static long min(long[] times)
- {
- long min = times.length > 0 ? times[0] : 0;
- for(int i = 0; i < times.length; i++)
- {
- min = Math.min(min, times[i]);
- }
- return min;
- }
-
- static long max(long[] times)
- {
- long max = times.length > 0 ? times[0] : 0;
- for(int i = 0; i < times.length; i++)
- {
- max = Math.max(max, times[i]);
- }
- return max;
- }
-
- static long avg(long[] times, long min, long max)
- {
- long sum = 0;
- for(int i = 0; i < times.length; i++)
- {
- sum += times[i];
- }
- sum -= min;
- sum -= max;
-
- return (sum / (times.length - 2));
- }
-
- public static void main(String[] argv) throws Exception
- {
- Config config = new Config();
- config.setOptions(argv);
-
- Connection con = config.createConnection();
- int size = config.getPayload();
- int ackMode = config.getAckMode();
- boolean persistent = config.usePersistentMessages();
- new Publisher(con, size, ackMode, persistent).test(config);
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java
deleted file mode 100644
index b55dac45c7..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.ping;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.requestreply.PingPongProducer;
-
-import org.apache.qpid.junit.extensions.TimingController;
-import org.apache.qpid.junit.extensions.TimingControllerAware;
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * PingAsyncTestPerf is a performance test that outputs multiple timings from its test method, using the timing controller
- * interface supplied by the test runner from a seperate listener thread. It differs from the {@link PingTestPerf} test
- * that it extends because it can output timings as replies are received, rather than waiting until all expected replies
- * are received. This is less 'blocky' than the tests in {@link PingTestPerf}, and provides a truer simulation of sending
- * and recieving clients working asynchronously.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><td> Responsibilities <th> Collaborations
- * <tr><td> Send many ping messages and output timings asynchronously on batches received.
- * </table>
- */
-public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerAware
-{
- private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class);
-
- /** Holds the name of the property to get the test results logging batch size. */
- public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize";
-
- /** Holds the default test results logging batch size. */
- public static final int TEST_RESULTS_BATCH_SIZE_DEFAULT = 1000;
-
- /** Used to hold the timing controller passed from the test runner. */
- private TimingController _timingController;
-
- /** Used to generate unique correlation ids for each test run. */
- private AtomicLong corellationIdGenerator = new AtomicLong();
-
- /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */
- private Map<String, PerCorrelationId> perCorrelationIds =
- Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
-
- /** Holds the batched results listener, that does logging on batch boundaries. */
- private BatchedResultsListener batchedResultsListener = null;
-
- /**
- * Creates a new asynchronous ping performance test with the specified name.
- *
- * @param name The test name.
- */
- public PingAsyncTestPerf(String name)
- {
- super(name);
-
- // Sets up the test parameters with defaults.
- testParameters.setPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME,
- Integer.toString(TEST_RESULTS_BATCH_SIZE_DEFAULT));
- }
-
- /**
- * Compile all the tests into a test suite.
- * @return The test suite to run. Should only contain testAsyncPingOk method.
- */
- public static Test suite()
- {
- // Build a new test suite
- TestSuite suite = new TestSuite("Ping Performance Tests");
-
- // Run performance tests in read committed mode.
- suite.addTest(new PingAsyncTestPerf("testAsyncPingOk"));
-
- return suite;
- }
-
- /**
- * Accepts a timing controller from the test runner.
- *
- * @param timingController The timing controller to register mutliple timings with.
- */
- public void setTimingController(TimingController timingController)
- {
- _timingController = timingController;
- }
-
- /**
- * Gets the timing controller passed in by the test runner.
- *
- * @return The timing controller passed in by the test runner.
- */
- public TimingController getTimingController()
- {
- return _timingController;
- }
-
- /**
- * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until
- * all replies have been received or a time out occurs before exiting this method.
- *
- * @param numPings The number of pings to send.
- * @throws Exception pass all errors out to the test harness
- */
- public void testAsyncPingOk(int numPings) throws Exception
- {
- // _logger.debug("public void testAsyncPingOk(int numPings): called");
-
- // get prefill count to update the expected count
- int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME);
-
- // Ensure that at least one ping was requeusted.
- if (numPings + preFill == 0)
- {
- _logger.error("Number of pings requested was zero.");
- fail("Number of pings requested was zero.");
- }
-
- // Get the per thread test setup to run the test through.
- PerThreadSetup perThreadSetup = threadSetup.get();
- PingClient pingClient = perThreadSetup._pingClient;
-
- // Advance the correlation id of messages to send, to make it unique for this run.
- perThreadSetup._correlationId = Long.toString(corellationIdGenerator.incrementAndGet());
- // String messageCorrelationId = perThreadSetup._correlationId;
- // _logger.debug("messageCorrelationId = " + messageCorrelationId);
-
-
- // Initialize the count and timing controller for the new correlation id.
- // This perCorrelationId is only used for controlling the test.
- // The PingClient itself uses its own perCorrelationId see in PingPongProducer
- PerCorrelationId perCorrelationId = new PerCorrelationId();
- TimingController tc = getTimingController().getControllerForCurrentThread();
- perCorrelationId._tc = tc;
- perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings + preFill);
- perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId);
-
- // Must be called before pingAndWaitForReply to setup the CorrelationID.
- // This is required because pingClient.start() will start all client threads
- // This means that the CorrelationID must be registered before hand.
- pingClient.setupCorrelationID(perThreadSetup._correlationId, perCorrelationId._expectedCount);
-
- // Start the client connection if:
- // 1) we are not in a SEND_ONLY test.
- // 2) if we have not yet started client because messages are sitting on broker.
- // This is either due to a preFill or a consume only test.
- if (!testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME) &&
- (preFill > 0 || testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME)))
- {
- pingClient.start();
- }
-
- // Send the requested number of messages, and wait until they have all been received.
- long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
- int numReplies = pingClient.pingAndWaitForReply(null, numPings , preFill, timeout, perThreadSetup._correlationId);
-
- // Check that all the replies were received and log a fail if they were not.
- if (numReplies < perCorrelationId._expectedCount)
- {
- System.out.println("##### " + numReplies + "replies, expected " + perCorrelationId._expectedCount + " #####");
- perCorrelationId._tc.completeTest(false, numPings - perCorrelationId._expectedCount);
- }
-
- // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up.
- perCorrelationIds.remove(perThreadSetup._correlationId);
- }
-
- /**
- * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
- */
- public void threadSetUp()
- {
- _logger.debug("public void threadSetUp(): called");
-
- try
- {
- // Call the set up method in the super class. This creates a PingClient pinger.
- super.threadSetUp();
-
- // Create the chained message listener, only if it has not already been created. This is set up with the
- // batch size property, to tell it what batch size to output results on. A synchronized block is used to
- // ensure that only one thread creates this.
- synchronized (this)
- {
- if (batchedResultsListener == null)
- {
- int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME));
- batchedResultsListener = new BatchedResultsListener(batchSize);
- }
- }
-
- // Get the set up that the super class created.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- // Register the chained message listener on the pinger to do its asynchronous test timings from.
- perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener);
- }
- catch (Exception e)
- {
- _logger.warn("There was an exception during per thread setup.", e);
- }
- }
-
- /**
- * BatchedResultsListener is a {@link PingPongProducer.ChainedMessageListener} that can be attached to the
- * pinger, in order to receive notifications about every message received and the number remaining to be
- * received. Whenever the number remaining crosses a batch size boundary this results listener outputs
- * a test timing for the actual number of messages received in the current batch.
- */
- private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener
- {
- /** The test results logging batch size. */
- int _batchSize;
-
- /** The latency recoreded for the batch */
- private long _batchLatency = 0;
-
- /**
- * Creates a results listener on the specified batch size.
- *
- * @param batchSize The batch size to use.
- */
- public BatchedResultsListener(int batchSize)
- {
- _batchSize = batchSize;
- }
-
- /**
- * This callback method is called from all of the pingers that this test creates. It uses the correlation id
- * from the message to identify the timing controller for the test thread that was responsible for sending those
- * messages.
- *
- * @param message The message.
- * @param remainingCount The count of messages remaining to be received with a particular correlation id.
- *
- * @throws JMSException Any underlying JMSException is allowed to fall through.
- */
- public void onMessage(Message message, int remainingCount, long latency) throws JMSException
- {
- // Record the latency for the whole batch
- _batchLatency += latency;
- // Check if a batch boundary has been crossed.
- if ((remainingCount % _batchSize) == 0)
- {
- // Extract the correlation id from the message.
- String correlationId = message.getJMSCorrelationID();
-
- /*_logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount
- + "): called on batch boundary for message id: " + correlationId + " with thread id: "
- + Thread.currentThread().getId());*/
-
- // Get the details for the correlation id and check that they are not null. They can become null
- // if a test times out.
- PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId);
- if (perCorrelationId != null)
- {
- // Get the timing controller and expected count for this correlation id.
- TimingController tc = perCorrelationId._tc;
- int expected = perCorrelationId._expectedCount;
-
- // Calculate how many messages were actually received in the last batch. This will be the batch size
- // except where the number expected is not a multiple of the batch size and this is the first remaining
- // count to cross a batch size boundary, in which case it will be the number expected modulo the batch
- // size.
- int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize;
-
- // Register a test result for the correlation id.
- try
- {
- // Record the total latency for the batch.
- // if batchSize=1 then this will just be the message latency
- tc.completeTest(true, receivedInBatch, null, _batchSize == 1 ? latency : _batchLatency);
- // Reset latency
- _batchLatency = 0;
- }
- catch (InterruptedException e)
- {
- // Ignore this. It means the test runner wants to stop as soon as possible.
- _logger.warn("Got InterruptedException.", e);
- }
- }
- // Else ignore, test timed out. Should log a fail here?
- }
- }
- }
-
- /**
- * Holds state specific to each correlation id, needed to output test results. This consists of the count of
- * the total expected number of messages, and the timing controller for the thread sending those message ids.
- */
- private static class PerCorrelationId
- {
- public int _expectedCount;
- public TimingController _tc;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java
deleted file mode 100644
index dcfc67d4fc..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.ping;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.requestreply.PingPongProducer;
-
-import javax.jms.Destination;
-
-import java.util.List;
-import java.util.Properties;
-
-/**
- * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer}
- * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues.
- * It is an all in one ping client, that produces and consumes its own pings.
- *
- * <p/>The constructor increments a count of the number of ping clients created. It is assumed that where many
- * are created they will all be run in parallel and be active in sending and consuming pings at the same time.
- * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear
- * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of
- * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these
- * conditions.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Create a ping producer that listens to its own pings <td> {@link PingPongProducer}
- * <tr><td> Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings.
- * </table>
- */
-public class PingClient extends PingPongProducer
-{
- /** Used for debugging. */
- private final Logger log = Logger.getLogger(PingClient.class);
-
- /** Used to count the number of ping clients created. */
- private static int _pingClientCount;
-
- /**
- * Creates a ping producer with the specified parameters, of which there are many. See the class level comments
- * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates
- * producer and consumer sessions on it, to send and recieve its pings and replies on.
- *
- * @param overrides Properties containing any desired overrides to the defaults.
- *
- * @throws Exception Any exceptions are allowed to fall through.
- */
- public PingClient(Properties overrides) throws Exception
- {
- super(overrides);
-
- _pingClientCount++;
- }
-
- /**
- * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the
- * effect of making this pinger listen to its own pings.
- *
- * @return The ping destinations.
- */
- public List<Destination> getReplyDestinations()
- {
- return _pingDestinations;
- }
-
- /**
- * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging.
- *
- * @return The scaling up of the number of expected pub/sub pings.
- */
- public int getConsumersPerDestination()
- {
- log.debug("public int getConsumersPerDestination(): called");
-
- if (_isUnique)
- {
- log.debug(_noOfConsumers + " consumer per destination.");
-
- return _noOfConsumers;
- }
- else
- {
- log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination.");
-
- return _pingClientCount * _noOfConsumers;
- }
- }
-
- public int getClientCount()
- {
- return _pingClientCount;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java
deleted file mode 100644
index a15897c82b..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.ping;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.requestreply.PingPongProducer;
-import org.apache.qpid.util.CommandLineParser;
-
-import org.apache.qpid.junit.extensions.util.MathUtils;
-import org.apache.qpid.junit.extensions.util.ParsedProperties;
-
-import javax.jms.*;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and
- * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop
- * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the
- * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with
- * failure conditions when using durable messaging.
- *
- * <p/>The events that can stop it from sending are input from the user on the console, failure of its connection to
- * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases
- * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings
- * with.
- *
- * <p/>The event to re-connect and attempt to recieve the pings is input from the user on the console.
- *
- * <p/>This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and
- * additionally accepts the following parameters:
- *
- * <p/><table><caption>Parameters</caption>
- * <tr><th> Parameter <th> Default <th> Comments
- * <tr><td> numMessages <td> 100 <td> The total number of messages to send.
- * <tr><td> numMessagesToAction <td> -1 <td> The number of messages to send before taking a custom 'action'.
- * <tr><td> duration <td> 30S <td> The length of time to ping for. (Format dDhHmMsS, for d days, h hours,
- * m minutes and s seconds).
- * </table>
- *
- * <p/>This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up
- * when no parameters are specified.
- *
- * <p/><table><caption>Parameters</caption>
- * <tr><th> Parameter <th> Default <th> Comments
- * <tr><td> uniqueDests <td> false <td> Prevents destination names being timestamped.
- * <tr><td> transacted <td> true <td> Only makes sense to test with transactions.
- * <tr><td> persistent <td> true <td> Only makes sense to test persistent.
- * <tr><td> durableDests <td> true <td> Should use durable queues with persistent messages.
- * <tr><td> commitBatchSize <td> 10
- * <tr><td> rate <td> 20 <td> Total default test time is 5 seconds.
- * </table>
- *
- * <p/>When a number of messages or duration is specified, this ping client will ping until the first of those limits
- * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will
- * wait for the second signal before receiving its pings.
- *
- * <p/>This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages
- * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method,
- * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide
- * custom behaviour with alternative implementations of this method (for example taking a backup).
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Send and receive pings.
- * <tr><td> Accept user input to signal stop sending.
- * <tr><td> Accept user input to signal start receiving.
- * <tr><td> Provide feedback on pings sent versus pings received.
- * <tr><td> Provide extension point for arbitrary action on a particular message count.
- * </table>
- */
-public class PingDurableClient extends PingPongProducer implements ExceptionListener
-{
- private static final Logger log = Logger.getLogger(PingDurableClient.class);
-
- public static final String NUM_MESSAGES_PROPNAME = "numMessages";
- public static final String NUM_MESSAGES_DEFAULT = "100";
- public static final String DURATION_PROPNAME = "duration";
- public static final String DURATION_DEFAULT = "30S";
- public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction";
- public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1";
-
- /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */
- private static final long TIME_OUT = 3000;
-
- static
- {
- defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT);
- defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT);
- defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false");
- defaults.setProperty(TRANSACTED_PROPNAME, "true");
- defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true");
- defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10");
- defaults.setProperty(RATE_PROPNAME, "20");
- defaults.setProperty(DURABLE_DESTS_PROPNAME, "true");
- defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT);
- }
-
- /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */
- private int numMessages;
-
- /** Holds the number of messages to send before taking triggering the action. */
- private int numMessagesToAction;
-
- /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */
- private long duration;
-
- /** Used to indciate that this application should terminate. Set by the shutdown hook. */
- private boolean terminate = false;
-
- /**
- * @throws Exception Any exceptions are allowed to fall through.
- */
- public PingDurableClient(Properties overrides) throws Exception
- {
- super(overrides);
- log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called");
-
- // Extract the additional configuration parameters.
- ParsedProperties properties = new ParsedProperties(defaults);
- properties.putAll(overrides);
-
- numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME);
- String durationSpec = properties.getProperty(DURATION_PROPNAME);
- numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME);
-
- if (durationSpec != null)
- {
- duration = MathUtils.parseDuration(durationSpec) * 1000000;
- }
- }
-
- /**
- * Starts the ping/wait/receive process.
- *
- * @param args The command line arguments.
- */
- public static void main(String[] args)
- {
- try
- {
- // Create a ping producer overriding its defaults with all options passed on the command line.
- Properties options =
- CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties());
- PingDurableClient pingProducer = new PingDurableClient(options);
-
- // Create a shutdown hook to terminate the ping-pong producer.
- Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook());
-
- // Ensure that the ping pong producer is registered to listen for exceptions on the connection too.
- // pingProducer.getConnection().setExceptionListener(pingProducer);
-
- // Run the test procedure.
- int sent = pingProducer.send();
- pingProducer.closeConnection();
- pingProducer.waitForUser("Press return to begin receiving the pings.");
- pingProducer.receive(sent);
-
- System.exit(0);
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- log.error("Top level handler caught execption.", e);
- System.exit(1);
- }
- }
-
- /**
- * Performs the main test procedure implemented by this ping client. See the class level comment for details.
- */
- protected int send() throws Exception
- {
- log.debug("public void sendWaitReceive(): called");
-
- log.debug("duration = " + duration);
- log.debug("numMessages = " + numMessages);
-
- if (duration > 0)
- {
- System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds.");
- }
-
- if (_rate > 0)
- {
- System.out.println("Sending at " + _rate + " messages per second.");
- }
-
- if (numMessages > 0)
- {
- System.out.println("Sending up to " + numMessages + " messages.");
- }
-
- // Establish the connection and the message producer.
- establishConnection(true, false);
- _connection.start();
-
- Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent);
-
- // Send pings until a terminating condition is received.
- boolean endCondition = false;
- int messagesSent = 0;
- int messagesCommitted = 0;
- int messagesNotCommitted = 0;
- long start = System.nanoTime();
-
- // Clear console in.
- clearConsole();
-
- while (!endCondition)
- {
- boolean committed = false;
-
- try
- {
- committed = sendMessage(messagesSent, message) && _transacted;
-
- messagesSent++;
- messagesNotCommitted++;
-
- // Keep count of the number of messsages currently committed and pending commit.
- if (committed)
- {
- log.debug("Adding " + messagesNotCommitted + " messages to the committed count.");
- messagesCommitted += messagesNotCommitted;
- messagesNotCommitted = 0;
-
- System.out.println("Commited: " + messagesCommitted);
- }
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException whilst sending.");
- _publish = false;
- }
-
- // Perform the arbitrary action if the number of messages sent has reached the right number.
- if (messagesSent == numMessagesToAction)
- {
- System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = "
- + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted);
- takeAction();
- }
-
- // Determine if the end condition has been met, based on the number of messages, time passed, errors on
- // the connection or user input.
- long now = System.nanoTime();
-
- if ((duration != 0) && ((now - start) > duration))
- {
- System.out.println("Send halted because duration expired.");
- endCondition = true;
- }
- else if ((numMessages != 0) && (messagesSent >= numMessages))
- {
- System.out.println("Send halted because # messages completed.");
- endCondition = true;
- }
- else if (System.in.available() > 0)
- {
- System.out.println("Send halted by user input.");
- endCondition = true;
-
- clearConsole();
- }
- else if (!_publish)
- {
- System.out.println("Send halted by error on the connection.");
- endCondition = true;
- }
- }
-
- log.debug("messagesSent = " + messagesSent);
- log.debug("messagesCommitted = " + messagesCommitted);
- log.debug("messagesNotCommitted = " + messagesNotCommitted);
-
- System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted
- + ", Messages not Committed = " + messagesNotCommitted);
-
- return messagesSent;
- }
-
- protected void closeConnection()
- {
- // Clean up the connection.
- try
- {
- close();
- }
- catch (JMSException e)
- {
- log.debug("There was an error whilst closing the connection: " + e, e);
- System.out.println("There was an error whilst closing the connection.");
-
- // Ignore as did best could manage to clean up.
- }
- }
-
- protected void receive(int messagesSent) throws Exception
- {
- // Re-establish the connection and the message consumer.
- _queueJVMSequenceID = new AtomicInteger();
- _queueSharedID = new AtomicInteger();
-
- establishConnection(false, true);
- _consumer[0].setMessageListener(null);
- _consumerConnection[0].start();
-
- // Try to receive all of the pings that were successfully sent.
- int messagesReceived = 0;
- boolean endCondition = false;
-
- while (!endCondition)
- {
- // Message received = _consumer.receiveNoWait();
- Message received = _consumer[0].receive(TIME_OUT);
- log.debug("received = " + received);
-
- if (received != null)
- {
- messagesReceived++;
- }
-
- // Determine if the end condition has been met, based on the number of messages and time passed since last
- // receiving a message.
- if (received == null)
- {
- System.out.println("Timed out.");
- endCondition = true;
- }
- else if (messagesReceived >= messagesSent)
- {
- System.out.println("Got all messages.");
- endCondition = true;
- }
- }
-
- // Ensure messages received are committed.
- if (_consTransacted)
- {
- try
- {
- _consumerSession[0].commit();
- System.out.println("Committed for all messages received.");
- }
- catch (JMSException e)
- {
- log.debug("Error during commit: " + e, e);
- System.out.println("Error during commit.");
- try
- {
- _consumerSession[0].rollback();
- System.out.println("Rolled back on all messages received.");
- }
- catch (JMSException e2)
- {
- log.debug("Error during rollback: " + e, e);
- System.out.println("Error on roll back of all messages received.");
- }
-
- }
- }
-
- log.debug("messagesReceived = " + messagesReceived);
-
- System.out.println("Messages received: " + messagesReceived);
-
- // Clean up the connection.
- close();
- }
-
- /**
- * Clears any pending input from the console.
- */
- private void clearConsole()
- {
- try
- {
- BufferedReader bis = new BufferedReader(new InputStreamReader(System.in));
-
- // System.in.skip(System.in.available());
- while (bis.ready())
- {
- bis.readLine();
- }
- }
- catch (IOException e)
- { }
- }
-
- /**
- * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the
- * effect of making this pinger listen to its own pings.
- *
- * @return The ping destinations.
- */
- public List<Destination> getReplyDestinations()
- {
- return _pingDestinations;
- }
-
- /**
- * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with
- * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the
- * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving
- * message should stop, not that the application should termiante.
- *
- * @return A shutdown hook for the ping loop.
- */
- public Thread getShutdownHook()
- {
- return new Thread(new Runnable()
- {
- public void run()
- {
- stop();
- terminate = true;
- }
- });
- }
-
- /**
- * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default
- * implementation does nothing.
- */
- public void takeAction()
- { }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java
deleted file mode 100644
index 5ba4004c56..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.ping;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.requestreply.PingPongProducer;
-
-import org.apache.qpid.junit.extensions.TimingController;
-import org.apache.qpid.junit.extensions.TimingControllerAware;
-import org.apache.qpid.junit.extensions.util.ParsedProperties;
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing
- * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for
- * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from
- * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than
- * waiting until all expected replies are received.
- *
- * <p/>This test does not output timings for every single ping message, as when running at high volume, writing the test
- * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The
- * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the
- * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}.
- *
- * <p/>The size parameter logged for each individual ping is set to the size of the batch of messages that the
- * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput
- * (messages / time) can be calculated in order to examine the relationship between throughput and latency.
- *
- * <p/><table id="crc"><caption>CRC Card</caption> <tr><td> Responsibilities <th> Collaborations <tr><td> Send many ping
- * messages and output timings for sampled individual pings. </table>
- */
-public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware
-{
- private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class);
-
- /** Holds the name of the property to get the test results logging batch size. */
- public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize";
-
- /** Holds the default test results logging batch size. */
- public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000;
-
- /** Used to hold the timing controller passed from the test runner. */
- private TimingController _timingController;
-
- /** Used to generate unique correlation ids for each test run. */
- private AtomicLong corellationIdGenerator = new AtomicLong();
-
- /**
- * Holds test specifics by correlation id. This consists of the expected number of messages and the timing
- * controler.
- */
- private Map<String, PerCorrelationId> perCorrelationIds =
- Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
-
- /** Holds the batched results listener, that does logging on batch boundaries. */
- private BatchedResultsListener batchedResultsListener = null;
-
- /**
- * Creates a new asynchronous ping performance test with the specified name.
- *
- * @param name The test name.
- */
- public PingLatencyTestPerf(String name)
- {
- super(name);
-
- // Sets up the test parameters with defaults.
- ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME,
- Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE));
- }
-
- /** Compile all the tests into a test suite. */
- public static Test suite()
- {
- // Build a new test suite
- TestSuite suite = new TestSuite("Ping Latency Tests");
-
- // Run performance tests in read committed mode.
- suite.addTest(new PingLatencyTestPerf("testPingLatency"));
-
- return suite;
- }
-
- /**
- * Accepts a timing controller from the test runner.
- *
- * @param timingController The timing controller to register mutliple timings with.
- */
- public void setTimingController(TimingController timingController)
- {
- _timingController = timingController;
- }
-
- /**
- * Gets the timing controller passed in by the test runner.
- *
- * @return The timing controller passed in by the test runner.
- */
- public TimingController getTimingController()
- {
- return _timingController;
- }
-
- /**
- * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all
- * replies have been received or a time out occurs before exiting this method.
- *
- * @param numPings The number of pings to send.
- */
- public void testPingLatency(int numPings) throws Exception
- {
- _logger.debug("public void testPingLatency(int numPings): called");
-
- // Ensure that at least one ping was requeusted.
- if (numPings == 0)
- {
- _logger.error("Number of pings requested was zero.");
- }
-
- // Get the per thread test setup to run the test through.
- PerThreadSetup perThreadSetup = threadSetup.get();
- PingClient pingClient = perThreadSetup._pingClient;
-
- // Advance the correlation id of messages to send, to make it unique for this run.
- String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet());
- _logger.debug("messageCorrelationId = " + messageCorrelationId);
-
- // Initialize the count and timing controller for the new correlation id.
- PerCorrelationId perCorrelationId = new PerCorrelationId();
- TimingController tc = getTimingController().getControllerForCurrentThread();
- perCorrelationId._tc = tc;
- perCorrelationId._expectedCount = numPings;
- perCorrelationIds.put(messageCorrelationId, perCorrelationId);
-
- // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these
- // messages.
- pingClient.setChainedMessageListener(batchedResultsListener);
-
- // Generate a sample message of the specified size.
- Message msg =
- pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
- testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
- testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
-
- // Send the requested number of messages, and wait until they have all been received.
- long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
- int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null);
-
- // Check that all the replies were received and log a fail if they were not.
- if (numReplies < numPings)
- {
- tc.completeTest(false, 0);
- }
-
- // Remove the chained message listener from the ping producer.
- pingClient.removeChainedMessageListener();
-
- // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up.
- perCorrelationIds.remove(messageCorrelationId);
- }
-
- /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */
- public void threadSetUp()
- {
- _logger.debug("public void threadSetUp(): called");
-
- try
- {
- // Call the set up method in the super class. This creates a PingClient pinger.
- super.threadSetUp();
-
- // Create the chained message listener, only if it has not already been created. This is set up with the
- // batch size property, to tell it what batch size to output results on. A synchronized block is used to
- // ensure that only one thread creates this.
- synchronized (this)
- {
- if (batchedResultsListener == null)
- {
- int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME));
- batchedResultsListener = new BatchedResultsListener(batchSize);
- }
- }
-
- // Get the set up that the super class created.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- // Register the chained message listener on the pinger to do its asynchronous test timings from.
- perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener);
- }
- catch (Exception e)
- {
- _logger.warn("There was an exception during per thread setup.", e);
- }
- }
-
- /**
- * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can
- * be attached to the pinger, in order to receive notifications about every message received and the number
- * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener
- * outputs a test timing for the actual number of messages received in the current batch.
- */
- private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener
- {
- /** The test results logging batch size. */
- int _batchSize;
- private boolean _strictAMQP;
-
- /**
- * Creates a results listener on the specified batch size.
- *
- * @param batchSize The batch size to use.
- */
- public BatchedResultsListener(int batchSize)
- {
- _batchSize = batchSize;
- _strictAMQP =
- Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP,
- AMQSession.STRICT_AMQP_DEFAULT));
- }
-
- /**
- * This callback method is called from all of the pingers that this test creates. It uses the correlation id
- * from the message to identify the timing controller for the test thread that was responsible for sending those
- * messages.
- *
- * @param message The message.
- * @param remainingCount The count of messages remaining to be received with a particular correlation id.
- *
- * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through.
- */
- public void onMessage(Message message, int remainingCount, long latency) throws JMSException
- {
- _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called");
-
- // Check if a batch boundary has been crossed.
- if ((remainingCount % _batchSize) == 0)
- {
- // Extract the correlation id from the message.
- String correlationId = message.getJMSCorrelationID();
-
- // Get the details for the correlation id and check that they are not null. They can become null
- // if a test times out.
- PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId);
- if (perCorrelationId != null)
- {
- // Get the timing controller and expected count for this correlation id.
- TimingController tc = perCorrelationId._tc;
- int expected = perCorrelationId._expectedCount;
-
- // Calculate how many messages were actually received in the last batch. This will be the batch size
- // except where the number expected is not a multiple of the batch size and this is the first remaining
- // count to cross a batch size boundary, in which case it will be the number expected modulo the batch
- // size.
- int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize;
-
- // Register a test result for the correlation id.
- try
- {
- tc.completeTest(true, receivedInBatch, latency);
- }
- catch (InterruptedException e)
- {
- // Ignore this. It means the test runner wants to stop as soon as possible.
- _logger.warn("Got InterruptedException.", e);
- }
- }
- // Else ignore, test timed out. Should log a fail here?
- }
- }
- }
-
- /**
- * Holds state specific to each correlation id, needed to output test results. This consists of the count of the
- * total expected number of messages, and the timing controller for the thread sending those message ids.
- */
- private static class PerCorrelationId
- {
- public int _expectedCount;
- public TimingController _tc;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java
deleted file mode 100644
index 2fe852af77..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.qpid.ping;
-
-import java.util.Properties;
-
-import javax.jms.Destination;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.ObjectMessage;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.message.TestMessageFactory;
-import org.apache.qpid.util.CommandLineParser;
-
-/**
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- */
-public class PingSendOnlyClient extends PingDurableClient
-{
- private static final Logger log = Logger.getLogger(PingSendOnlyClient.class);
-
- public PingSendOnlyClient(Properties overrides) throws Exception
- {
- super(overrides);
- }
-
- /**
- * Starts the ping/wait/receive process.
- *
- * @param args The command line arguments.
- */
- public static void main(String[] args)
- {
- try
- {
- // Create a ping producer overriding its defaults with all options passed on the command line.
- Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties());
- PingSendOnlyClient pingProducer = new PingSendOnlyClient(options);
-
- // Create a shutdown hook to terminate the ping-pong producer.
- Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook());
-
- // Ensure that the ping pong producer is registered to listen for exceptions on the connection too.
- // pingProducer.getConnection().setExceptionListener(pingProducer);
-
- // Run the test procedure.
- pingProducer.send();
- pingProducer.waitForUser("Press return to close connection and quit.");
- pingProducer.closeConnection();
-
- System.exit(0);
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- log.error("Top level handler caught execption.", e);
- System.exit(1);
- }
- }
-
- public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException
- {
- Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize);
-
- // Timestamp the message in nanoseconds.
- msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
-
- return msg;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java
deleted file mode 100644
index cf16abc596..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.ping;
-
-import junit.framework.Assert;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.requestreply.PingPongProducer;
-
-import org.apache.qpid.junit.extensions.AsymptoticTestCase;
-import org.apache.qpid.junit.extensions.TestThreadAware;
-import org.apache.qpid.junit.extensions.util.ParsedProperties;
-import org.apache.qpid.junit.extensions.util.TestContextProperties;
-
-import javax.jms.*;
-
-/**
- * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times
- * simultaneously to simluate many clients/producers/connections.
- *
- * <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of a single
- * full round trip ping. This test may be scaled up using a suitable JUnit test runner.
- *
- * <p/>The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a
- * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run,
- * except if the connection is lost in which case an attempt to re-establish the setup is made.
- *
- * <p/>The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that
- * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the
- * temporary queue.
- *
- * <p/>Configurable test properties: message size, transacted or not, persistent or not. Broker connection details.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- */
-public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware
-{
- private static Logger _logger = Logger.getLogger(PingTestPerf.class);
-
- /** Thread local to hold the per-thread test setup fields. */
- ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
-
- /** Holds a property reader to extract the test parameters from. */
- protected ParsedProperties testParameters =
- TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/);
-
- public PingTestPerf(String name)
- {
- super(name);
-
- _logger.debug("testParameters = " + testParameters);
- }
-
- /**
- * Compile all the tests into a test suite.
- * @return The test method testPingOk.
- */
- public static Test suite()
- {
- // Build a new test suite
- TestSuite suite = new TestSuite("Ping Performance Tests");
-
- // Run performance tests in read committed mode.
- suite.addTest(new PingTestPerf("testPingOk"));
-
- return suite;
- }
-
- public void testPingOk(int numPings) throws Exception
- {
- if (numPings == 0)
- {
- Assert.fail("Number of pings requested was zero.");
- }
-
- // Get the per thread test setup to run the test through.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- if (perThreadSetup == null)
- {
- Assert.fail("Could not get per thread test setup, it was null.");
- }
-
- // Generate a sample message. This message is already time stamped and has its reply-to destination set.
- Message msg =
- perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
- testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
- testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
-
- // start the test
- long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
- int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null);
-
- // Fail the test if the timeout was exceeded.
- if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings))
- {
- Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = "
- + numReplies);
- }
- }
-
- /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */
- public void threadSetUp()
- {
- _logger.debug("public void threadSetUp(): called");
-
- try
- {
- PerThreadSetup perThreadSetup = new PerThreadSetup();
-
- // This is synchronized because there is a race condition, which causes one connection to sleep if
- // all threads try to create connection concurrently.
- synchronized (this)
- {
- // Establish a client to ping a Destination and listen the reply back from same Destination
- perThreadSetup._pingClient = new PingClient(testParameters);
- perThreadSetup._pingClient.establishConnection(true, true);
- }
-
- // Attach the per-thread set to the thread.
- threadSetup.set(perThreadSetup);
- }
- catch (Exception e)
- {
- _logger.warn("There was an exception during per thread setup.", e);
- }
- }
-
- /**
- * Called after all threads have completed their setup.
- */
- public void postThreadSetUp()
- {
- _logger.debug("public void postThreadSetUp(): called");
-
- PerThreadSetup perThreadSetup = threadSetup.get();
- // Prefill the broker unless we are in consume only mode.
- int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME);
- if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) && preFill > 0)
- {
- try
- {
- // Manually set the correlation ID to 1. This is not ideal but it is the
- // value that the main test loop will use.
- perThreadSetup._pingClient.pingNoWaitForReply(null, preFill, String.valueOf(perThreadSetup._pingClient.getClientCount()));
-
- // Note with a large preFill and non-tx session the messages will be
- // rapidly pushed in to the mina buffers. OOM's are a real risk here.
- // Should perhaps consider using a TX session for the prefill.
-
- long delayBeforeConsume = testParameters.getPropertyAsLong(PingPongProducer.DELAY_BEFORE_CONSUME_PROPNAME);
-
- // Only delay if we are
- // not doing send only
- // and we have consumers
- // and a delayBeforeConsume
- if (!(testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME))
- && (testParameters.getPropertyAsInteger(PingPongProducer.NUM_CONSUMERS_PROPNAME) > 0)
- && delayBeforeConsume > 0)
- {
-
- boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME);
- // Only do logging if in verbose mode.
- if (verbose)
- {
- if (delayBeforeConsume > 60000)
- {
- long minutes = delayBeforeConsume / 60000;
- long seconds = (delayBeforeConsume - (minutes * 60000)) / 1000;
- long ms = delayBeforeConsume - (minutes * 60000) - (seconds * 1000);
- _logger.info("Delaying for " + minutes + "m " + seconds + "s " + ms + "ms before starting test.");
- }
- else
- {
- _logger.info("Delaying for " + delayBeforeConsume + "ms before starting test.");
- }
- }
-
- Thread.sleep(delayBeforeConsume);
-
- if (verbose)
- {
- _logger.info("Starting Test.");
- }
- }
-
- // We can't start the client's here as the test client has not yet been configured to receieve messages.
- // only when the test method is executed will the correlationID map be set up and ready to consume
- // the messages we have sent here.
- }
- catch (Exception e)
- {
- _logger.warn("There was an exception during per thread setup.", e);
- }
- }
- else //Only start the consumer if we are not preFilling.
- {
- // Start the consumers, unless we have data on the broker
- // already this is signified by being in consume_only, we will
- // start the clients after setting up the correlation IDs.
- // We should also not start the clients if we are in Send only
- if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) &&
- !(testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME)))
- {
- // Start the client connection
- try
- {
- perThreadSetup._pingClient.start();
- }
- catch (JMSException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
- }
- }
- }
-
- /**
- * Performs test fixture clean
- */
- public void threadTearDown()
- {
- _logger.debug("public void threadTearDown(): called");
-
- try
- {
- // Get the per thread test fixture.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- // Close the pingers so that it cleans up its connection cleanly.
- synchronized (this)
- {
- if ((perThreadSetup != null) && (perThreadSetup._pingClient != null))
- {
- perThreadSetup._pingClient.close();
- }
- }
- }
- catch (JMSException e)
- {
- _logger.warn("There was an exception during per thread tear down.");
- }
- finally
- {
- // Ensure the per thread fixture is reclaimed.
- threadSetup.remove();
- }
- }
-
- protected static class PerThreadSetup
- {
- /**
- * Holds the test ping client.
- */
- protected PingClient _pingClient;
- protected String _correlationId;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
deleted file mode 100644
index 8e010ccf07..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.requestreply;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import javax.jms.*;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.Session;
-import org.apache.qpid.topic.Config;
-import org.apache.qpid.exchange.ExchangeDefaults;
-
-/**
- * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return
- * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes
- * too.
- *
- * <p/>The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages
- * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique
- * temporary queue or the correlation id to correlate the original message to the reply.
- *
- * <p/>There is a verbose mode flag which causes information about each ping to be output to the console
- * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should
- * be disabled for real timing tests as writing to the console will slow things down.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Bounce back messages to their reply to destination.
- * <tr><td> Provide command line invocation to start the bounce back on a configurable broker url.
- * </table>
- *
- * @todo Replace the command line parsing with a neater tool.
- *
- * @todo Make verbose accept a number of messages, only prints to console every X messages.
- */
-public class PingPongBouncer implements MessageListener
-{
- private static final Logger _logger = Logger.getLogger(PingPongBouncer.class);
-
- /** The default prefetch size for the message consumer. */
- private static final int PREFETCH = 1;
-
- /** The default no local flag for the message consumer. */
- private static final boolean NO_LOCAL = true;
-
- private static final String DEFAULT_DESTINATION_NAME = "ping";
-
- /** The default exclusive flag for the message consumer. */
- private static final boolean EXCLUSIVE = false;
-
- /** A convenient formatter to use when time stamping output. */
- protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
-
- /** Used to indicate that the reply generator should log timing info to the console (logger info level). */
- private boolean _verbose = false;
-
- /** Determines whether this bounce back client bounces back messages persistently. */
- private boolean _persistent = false;
-
- private Destination _consumerDestination;
-
- /** Keeps track of the response destination of the previous message for the last reply to producer cache. */
- private Destination _lastResponseDest;
-
- /** The producer for sending replies with. */
- private MessageProducer _replyProducer;
-
- /** The consumer controlSession. */
- private Session _consumerSession;
-
- /** The producer controlSession. */
- private Session _producerSession;
-
- /** Holds the connection to the broker. */
- private AMQConnection _connection;
-
- /** Flag used to indicate if this is a point to point or pub/sub ping client. */
- private boolean _isPubSub = false;
-
- /**
- * This flag is used to indicate that the user should be prompted to kill a broker, in order to test
- * failover, immediately before committing a transaction.
- */
- protected boolean _failBeforeCommit = false;
-
- /**
- * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test
- * failover, immediate after committing a transaction.
- */
- protected boolean _failAfterCommit = false;
-
- /**
- * Creates a PingPongBouncer on the specified producer and consumer sessions.
- *
- * @param brokerDetails The addresses of the brokers to connect to.
- * @param username The broker username.
- * @param password The broker password.
- * @param virtualpath The virtual host name within the broker.
- * @param destinationName The name of the queue to receive pings on
- * (or root of the queue name where many queues are generated).
- * @param persistent A flag to indicate that persistent message should be used.
- * @param transacted A flag to indicate that pings should be sent within transactions.
- * @param selector A message selector to filter received pings with.
- * @param verbose A flag to indicate that message timings should be sent to the console.
- *
- * @throws Exception All underlying exceptions allowed to fall through. This is only test code...
- */
- public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath,
- String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose,
- boolean pubsub) throws Exception
- {
- // Create a client id to uniquely identify this client.
- InetAddress address = InetAddress.getLocalHost();
- String clientId = address.getHostName() + System.currentTimeMillis();
- _verbose = verbose;
- _persistent = persistent;
- setPubSub(pubsub);
- // Connect to the broker.
- setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath));
- _logger.info("Connected with URL:" + getConnection().toURL());
-
- // Set up the failover notifier.
- getConnection().setConnectionListener(new FailoverNotifier());
-
- // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the
- // command line option.
- _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
- _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
-
- // Create the queue to listen for message on.
- createConsumerDestination(destinationName);
- MessageConsumer consumer =
- _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector);
-
- // Create a producer for the replies, without a default destination.
- _replyProducer = _producerSession.createProducer(null);
- _replyProducer.setDisableMessageTimestamp(true);
- _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
-
- // Set this up to listen for messages on the queue.
- consumer.setMessageListener(this);
- }
-
- /**
- * Starts a stand alone ping-pong client running in verbose mode.
- *
- * @param args
- */
- public static void main(String[] args) throws Exception
- {
- System.out.println("Starting...");
-
- // Display help on the command line.
- if (args.length == 0)
- {
- _logger.info("Running test with default values...");
- //usage();
- //System.exit(0);
- }
-
- // Extract all command line parameters.
- Config config = new Config();
- config.setOptions(args);
- String brokerDetails = config.getHost() + ":" + config.getPort();
- String virtualpath = "test";
- String destinationName = config.getDestination();
- if (destinationName == null)
- {
- destinationName = DEFAULT_DESTINATION_NAME;
- }
-
- String selector = config.getSelector();
- boolean transacted = config.isTransacted();
- boolean persistent = config.usePersistentMessages();
- boolean pubsub = config.isPubSub();
- boolean verbose = true;
-
- //String selector = null;
-
- // Instantiate the ping pong client with the command line options and start it running.
- PingPongBouncer pingBouncer =
- new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted,
- selector, verbose, pubsub);
- pingBouncer.getConnection().start();
-
- System.out.println("Waiting...");
- }
-
- private static void usage()
- {
- System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n"
- + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n"
- + "-persistent : (true/false). Default is false\n"
- + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n");
- }
-
- /**
- * This is a callback method that is notified of all messages for which this has been registered as a message
- * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to
- * destination of the message.
- *
- * @param message The message that triggered this callback.
- */
- public void onMessage(Message message)
- {
- try
- {
- String messageCorrelationId = message.getJMSCorrelationID();
- if (_verbose)
- {
- _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, "
- + messageCorrelationId);
- }
-
- // Get the reply to destination from the message and check it is set.
- Destination responseDest = message.getJMSReplyTo();
-
- if (responseDest == null)
- {
- _logger.debug("Cannot send reply because reply-to destination is null.");
-
- return;
- }
-
- // Spew out some timing information if verbose mode is on.
- if (_verbose)
- {
- Long timestamp = message.getLongProperty("timestamp");
-
- if (timestamp != null)
- {
- long diff = System.currentTimeMillis() - timestamp;
- _logger.info("Time to bounce point: " + diff);
- }
- }
-
- // Correlate the reply to the original.
- message.setJMSCorrelationID(messageCorrelationId);
-
- // Send the receieved message as the pong reply.
- _replyProducer.send(responseDest, message);
-
- if (_verbose)
- {
- _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, "
- + messageCorrelationId);
- }
-
- // Commit the transaction if running in transactional mode.
- commitTx(_producerSession);
- }
- catch (JMSException e)
- {
- _logger.debug("There was a JMSException: " + e.getMessage(), e);
- }
- }
-
- /**
- * Gets the underlying connection that this ping client is running on.
- *
- * @return The underlying connection that this ping client is running on.
- */
- public AMQConnection getConnection()
- {
- return _connection;
- }
-
- /**
- * Sets the connection that this ping client is using.
- *
- * @param connection The ping connection.
- */
- public void setConnection(AMQConnection connection)
- {
- this._connection = connection;
- }
-
- /**
- * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic.
- *
- * @param pubsub <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public void setPubSub(boolean pubsub)
- {
- _isPubSub = pubsub;
- }
-
- /**
- * Checks whether this client is a p2p or pub/sub ping client.
- *
- * @return <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public boolean isPubSub()
- {
- return _isPubSub;
- }
-
- /**
- * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not
- * a transactional controlSession, this method does nothing.
- *
- * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
- * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
- * after the commit is applied.
- *
- * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
- */
- protected void commitTx(Session session) throws JMSException
- {
- if (session.getTransacted())
- {
- try
- {
- if (_failBeforeCommit)
- {
- _logger.debug("Failing Before Commit");
- doFailover();
- }
-
- session.commit();
-
- if (_failAfterCommit)
- {
- _logger.debug("Failing After Commit");
- doFailover();
- }
-
- _logger.debug("Session Commited.");
- }
- catch (JMSException e)
- {
- _logger.trace("JMSException on commit:" + e.getMessage(), e);
-
- try
- {
- session.rollback();
- _logger.debug("Message rolled back.");
- }
- catch (JMSException jmse)
- {
- _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
-
- // Both commit and rollback failed. Throw the rollback exception.
- throw jmse;
- }
- }
- }
- }
-
- /**
- * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- *
- * @param broker The name of the broker to terminate.
- */
- protected void doFailover(String broker)
- {
- System.out.println("Kill Broker " + broker + " now.");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
- }
-
- /**
- * Prompts the user to terminate the broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- */
- protected void doFailover()
- {
- System.out.println("Kill Broker now.");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
-
- }
-
- private void createConsumerDestination(String name)
- {
- if (isPubSub())
- {
- _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name);
- }
- else
- {
- _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name);
- }
- }
-
- /**
- * A connection listener that logs out any failover complete events. Could do more interesting things with this
- * at some point...
- */
- public static class FailoverNotifier implements ConnectionListener
- {
- public void bytesSent(long count)
- { }
-
- public void bytesReceived(long count)
- { }
-
- public boolean preFailover(boolean redirect)
- {
- return true;
- }
-
- public boolean preResubscribe()
- {
- return true;
- }
-
- public void failoverComplete()
- {
- _logger.info("App got failover complete callback.");
- }
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
deleted file mode 100644
index 639b0c72ba..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
+++ /dev/null
@@ -1,1818 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.requestreply;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.test.framework.TestUtils;
-
-import org.apache.qpid.junit.extensions.BatchedThrottle;
-import org.apache.qpid.junit.extensions.Throttle;
-import org.apache.qpid.junit.extensions.util.CommandLineParser;
-import org.apache.qpid.junit.extensions.util.ParsedProperties;
-
-import javax.jms.*;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import java.io.*;
-import java.net.InetAddress;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may
- * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens
- * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping
- * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour
- * configurable.
- *
- * <p/>The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This
- * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation
- * id in the ping to be bounced back in the reply correlation id.
- *
- * <p/>This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It
- * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within
- * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover
- * testing. A complete list of accepted parameters, default values and comments on their usage is provided here:
- *
- * <p/><table><caption>Parameters</caption>
- * <tr><th> Parameter <th> Default <th> Comments
- * <tr><td> messageSize <td> 0 <td> Message size in bytes. Not including any headers.
- * <tr><td> destinationName <td> ping <td> The root name to use to generate destination names to ping.
- * <tr><td> persistent <td> false <td> Determines whether peristent delivery is used.
- * <tr><td> transacted <td> false <td> Determines whether messages are sent/received in transactions.
- * <tr><td> broker <td> tcp://localhost:5672 <td> Determines the broker to connect to.
- * <tr><td> virtualHost <td> test <td> Determines the virtual host to send all ping over.
- * <tr><td> rate <td> 0 <td> The maximum rate (in hertz) to send messages at. 0 means no limit.
- * <tr><td> verbose <td> false <td> The verbose flag for debugging. Prints to console on every message.
- * <tr><td> pubsub <td> false <td> Whether to ping topics or queues. Uses p2p by default.
- * <tr><td> failAfterCommit <td> false <td> Whether to prompt user to kill broker after a commit batch.
- * <tr><td> failBeforeCommit <td> false <td> Whether to prompt user to kill broker before a commit batch.
- * <tr><td> failAfterSend <td> false <td> Whether to prompt user to kill broker after a send.
- * <tr><td> failBeforeSend <td> false <td> Whether to prompt user to kill broker before a send.
- * <tr><td> failOnce <td> true <td> Whether to prompt for failover only once.
- * <tr><td> username <td> guest <td> The username to access the broker with.
- * <tr><td> password <td> guest <td> The password to access the broker with.
- * <tr><td> selector <td> null <td> Not used. Defines a message selector to filter pings with.
- * <tr><td> destinationCount <td> 1 <td> The number of destinations to send pings to.
- * <tr><td> numConsumers <td> 1 <td> The number of consumers on each destination.
- * <tr><td> timeout <td> 30000 <td> In milliseconds. The timeout to stop waiting for replies.
- * <tr><td> commitBatchSize <td> 1 <td> The number of messages per transaction in transactional mode.
- * <tr><td> uniqueDests <td> true <td> Whether each receivers only listens to one ping destination or all.
- * <tr><td> durableDests <td> false <td> Whether or not durable destinations are used.
- * <tr><td> ackMode <td> AUTO_ACK <td> The message acknowledgement mode. Possible values are:
- * 0 - SESSION_TRANSACTED
- * 1 - AUTO_ACKNOWLEDGE
- * 2 - CLIENT_ACKNOWLEDGE
- * 3 - DUPS_OK_ACKNOWLEDGE
- * 257 - NO_ACKNOWLEDGE
- * 258 - PRE_ACKNOWLEDGE
- * <tr><td> consTransacted <td> false <td> Whether or not consumers use transactions. Defaults to the same value
- * as the 'transacted' option if not seperately defined.
- * <tr><td> consAckMode <td> AUTO_ACK <td> The message acknowledgement mode for consumers. Defaults to the same
- * value as 'ackMode' if not seperately defined.
- * <tr><td> maxPending <td> 0 <td> The maximum size in bytes, of messages sent but not yet received.
- * Limits the volume of messages currently buffered on the client
- * or broker. Can help scale test clients by limiting amount of buffered
- * data to avoid out of memory errors.
- * </table>
- *
- * <p/>This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop
- * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by
- * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also
- * registered to terminate the ping-pong loop cleanly.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide a ping and wait for all responses cycle.
- * <tr><td> Provide command line invocation to loop the ping cycle on a configurable broker url.
- * </table>
- *
- * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair.
- * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a
- * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last
- * message waits until all other messages have been handled before releasing producers but allows messages to be
- * processed concurrently, unlike the current synchronized block.
- */
-public class PingPongProducer implements Runnable, ExceptionListener
-{
- /** Used for debugging. */
- private static final Logger log = Logger.getLogger(PingPongProducer.class);
-
- /** Holds the name of the property to determine whether of not client id is overridden at connection time. */
- public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId";
-
- /** Holds the default value of the override client id flag. */
- public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false";
-
- /** Holds the name of the property to define the JNDI factory name with. */
- public static final String FACTORY_NAME_PROPNAME = "factoryName";
-
- /** Holds the default JNDI name of the connection factory. */
- public static final String FACTORY_NAME_DEAFULT = "local";
-
- /** Holds the name of the property to set the JNDI initial context properties with. */
- public static final String FILE_PROPERTIES_PROPNAME = "properties";
-
- /** Holds the default file name of the JNDI initial context properties. */
- public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties";
-
- /** Holds the name of the property to get the test message size from. */
- public static final String MESSAGE_SIZE_PROPNAME = "messageSize";
-
- /** Used to set up a default message size. */
- public static final int MESSAGE_SIZE_DEAFULT = 0;
-
- /** Holds the name of the property to get the ping queue name from. */
- public static final String PING_QUEUE_NAME_PROPNAME = "destinationName";
-
- /** Holds the name of the default destination to send pings on. */
- public static final String PING_QUEUE_NAME_DEFAULT = "ping";
-
- /** Holds the name of the property to get the queue name postfix from. */
- public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix";
-
- /** Holds the default queue name postfix value. */
- public static final String QUEUE_NAME_POSTFIX_DEFAULT = "";
-
- /** Holds the name of the property to get the test delivery mode from. */
- public static final String PERSISTENT_MODE_PROPNAME = "persistent";
-
- /** Holds the message delivery mode to use for the test. */
- public static final boolean PERSISTENT_MODE_DEFAULT = false;
-
- /** Holds the name of the property to get the test transactional mode from. */
- public static final String TRANSACTED_PROPNAME = "transacted";
-
- /** Holds the transactional mode to use for the test. */
- public static final boolean TRANSACTED_DEFAULT = false;
-
- /** Holds the name of the property to get the test consumer transacted mode from. */
- public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted";
-
- /** Holds the consumer transactional mode default setting. */
- public static final boolean CONSUMER_TRANSACTED_DEFAULT = false;
-
- /** Holds the name of the property to get the test broker url from. */
- public static final String BROKER_PROPNAME = "broker";
-
- /** Holds the default broker url for the test. */
- public static final String BROKER_DEFAULT = "tcp://localhost:5672";
-
- /** Holds the name of the property to get the test broker virtual path. */
- public static final String VIRTUAL_HOST_PROPNAME = "virtualHost";
-
- /** Holds the default virtual path for the test. */
- public static final String VIRTUAL_HOST_DEFAULT = "";
-
- /** Holds the name of the property to get the message rate from. */
- public static final String RATE_PROPNAME = "rate";
-
- /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */
- public static final int RATE_DEFAULT = 0;
-
- /** Holds the name of the property to get the verbose mode proeprty from. */
- public static final String VERBOSE_PROPNAME = "verbose";
-
- /** Holds the default verbose mode. */
- public static final boolean VERBOSE_DEFAULT = false;
-
- /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */
- public static final String PUBSUB_PROPNAME = "pubsub";
-
- /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */
- public static final boolean PUBSUB_DEFAULT = false;
-
- /** Holds the name of the property to get the fail after commit flag from. */
- public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit";
-
- /** Holds the default failover after commit test flag. */
- public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false;
-
- /** Holds the name of the proeprty to get the fail before commit flag from. */
- public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit";
-
- /** Holds the default failover before commit test flag. */
- public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false;
-
- /** Holds the name of the proeprty to get the fail after send flag from. */
- public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend";
-
- /** Holds the default failover after send test flag. */
- public static final boolean FAIL_AFTER_SEND_DEFAULT = false;
-
- /** Holds the name of the property to get the fail before send flag from. */
- public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend";
-
- /** Holds the default failover before send test flag. */
- public static final boolean FAIL_BEFORE_SEND_DEFAULT = false;
-
- /** Holds the name of the property to get the fail once flag from. */
- public static final String FAIL_ONCE_PROPNAME = "failOnce";
-
- /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */
- public static final boolean FAIL_ONCE_DEFAULT = true;
-
- /** Holds the name of the property to get the broker access username from. */
- public static final String USERNAME_PROPNAME = "username";
-
- /** Holds the default broker log on username. */
- public static final String USERNAME_DEFAULT = "guest";
-
- /** Holds the name of the property to get the broker access password from. */
- public static final String PASSWORD_PROPNAME = "password";
-
- /** Holds the default broker log on password. */
- public static final String PASSWORD_DEFAULT = "guest";
-
- /** Holds the name of the proeprty to get the. */
- public static final String SELECTOR_PROPNAME = "selector";
-
- /** Holds the default message selector. */
- public static final String SELECTOR_DEFAULT = "";
-
- /** Holds the name of the property to get the destination count from. */
- public static final String DESTINATION_COUNT_PROPNAME = "destinationCount";
-
- /** Defines the default number of destinations to ping. */
- public static final int DESTINATION_COUNT_DEFAULT = 1;
-
- /** Holds the name of the property to get the number of consumers per destination from. */
- public static final String NUM_CONSUMERS_PROPNAME = "numConsumers";
-
- /** Defines the default number consumers per destination. */
- public static final int NUM_CONSUMERS_DEFAULT = 1;
-
- /** Holds the name of the property to get the waiting timeout for response messages. */
- public static final String TIMEOUT_PROPNAME = "timeout";
-
- /** Default time to wait before assuming that a ping has timed out. */
- public static final long TIMEOUT_DEFAULT = 30000;
-
- /** Holds the name of the property to get the commit batch size from. */
- public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize";
-
- /** Defines the default number of pings to send in each transaction when running transactionally. */
- public static final int TX_BATCH_SIZE_DEFAULT = 1;
-
- /** Holds the name of the property to get the unique destinations flag from. */
- public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests";
-
- /** Defines the default value for the unique destinations property. */
- public static final boolean UNIQUE_DESTS_DEFAULT = true;
-
- /** Holds the name of the property to get the durable destinations flag from. */
- public static final String DURABLE_DESTS_PROPNAME = "durableDests";
-
- /** Defines the default value of the durable destinations flag. */
- public static final boolean DURABLE_DESTS_DEFAULT = false;
-
- /** Holds the name of the proeprty to get the message acknowledgement mode from. */
- public static final String ACK_MODE_PROPNAME = "ackMode";
-
- /** Defines the default message acknowledgement mode. */
- public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE;
-
- /** Holds the name of the property to get the consumers message acknowledgement mode from. */
- public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode";
-
- /** Defines the default consumers message acknowledgement mode. */
- public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE;
-
- /** Holds the name of the property to get the maximum pending message size setting from. */
- public static final String MAX_PENDING_PROPNAME = "maxPending";
-
- /** Defines the default value for the maximum pending message size setting. 0 means no limit. */
- public static final int MAX_PENDING_DEFAULT = 0;
-
- /** Defines the default prefetch size to use when consuming messages. */
- public static final int PREFETCH_DEFAULT = 100;
-
- /** Defines the default value of the no local flag to use when consuming messages. */
- public static final boolean NO_LOCAL_DEFAULT = false;
-
- /** Defines the default value of the exclusive flag to use when consuming messages. */
- public static final boolean EXCLUSIVE_DEFAULT = false;
-
- /** Holds the name of the property to store nanosecond timestamps in ping messages with. */
- public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp";
-
- /** Holds the name of the property to get the number of message to prefill the broker with before starting the main test. */
- public static final String PREFILL_PROPNAME = "preFill";
-
- /** Defines the default value for the number of messages to prefill. 0,default, no messages. */
- public static final int PREFILL_DEFAULT = 0;
-
- /** Holds the name of the property to get the delay to wait in ms before starting the main test after having prefilled. */
- public static final String DELAY_BEFORE_CONSUME_PROPNAME = "delayBeforeConsume";
-
- /** Defines the default value for delay in ms to wait before starting thet test run. 0,default, no delay. */
- public static final long DELAY_BEFORE_CONSUME = 0;
-
- /** Holds the name of the property to get when no messasges should be sent. */
- public static final String CONSUME_ONLY_PROPNAME = "consumeOnly";
-
- /** Defines the default value of the consumeOnly flag to use when publishing messages is not desired. */
- public static final boolean CONSUME_ONLY_DEFAULT = false;
-
- /** Holds the name of the property to get when no messasges should be sent. */
- public static final String SEND_ONLY_PROPNAME = "sendOnly";
-
- /** Defines the default value of the consumeOnly flag to use when publishing messages is not desired. */
- public static final boolean SEND_ONLY_DEFAULT = false;
-
- /** Holds the default configuration properties. */
- public static ParsedProperties defaults = new ParsedProperties();
-
- static
- {
- defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT);
- defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT);
- defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT);
- defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
- defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT);
- defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT);
- defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT);
- defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT);
- defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT);
- defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT);
- defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT);
- defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT);
- defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT);
- defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT);
- defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT);
- defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT);
- defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT);
- defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT);
- defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT);
- defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT);
- defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT);
- defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT);
- defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT);
- defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT);
- defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT);
- defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT);
- defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT);
- defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT);
- defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT);
- defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT);
- defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT);
- defaults.setPropertyIfNull(PREFILL_PROPNAME, PREFILL_DEFAULT);
- defaults.setPropertyIfNull(DELAY_BEFORE_CONSUME_PROPNAME, DELAY_BEFORE_CONSUME);
- defaults.setPropertyIfNull(CONSUME_ONLY_PROPNAME, CONSUME_ONLY_DEFAULT);
- defaults.setPropertyIfNull(SEND_ONLY_PROPNAME, SEND_ONLY_DEFAULT);
- }
-
- /** Allows setting of client ID on the connection, rather than through the connection URL. */
- protected boolean _overrideClientId;
-
- /** Holds the JNDI name of the JMS connection factory. */
- protected String _factoryName;
-
- /** Holds the name of the properties file to configure JNDI with. */
- protected String _fileProperties;
-
- /** Holds the broker url. */
- protected String _brokerDetails;
-
- /** Holds the username to access the broker with. */
- protected String _username;
-
- /** Holds the password to access the broker with. */
- protected String _password;
-
- /** Holds the virtual host on the broker to run the tests through. */
- protected String _virtualpath;
-
- /** Holds the root name from which to generate test destination names. */
- protected String _destinationName;
-
- /** Holds the default queue name postfix value. */
- protected String _queueNamePostfix;
-
- /** Holds the message selector to filter the pings with. */
- protected String _selector;
-
- /** Holds the producers transactional mode flag. */
- protected boolean _transacted;
-
- /** Holds the consumers transactional mode flag. */
- protected boolean _consTransacted;
-
- /** Determines whether this producer sends persistent messages. */
- protected boolean _persistent;
-
- /** Holds the acknowledgement mode used for the producers. */
- protected int _ackMode;
-
- /** Holds the acknowledgement mode setting for the consumers. */
- protected int _consAckMode;
-
- /** Determines what size of messages this producer sends. */
- protected int _messageSize;
-
- /** Used to indicate that the ping loop should print out whenever it pings. */
- protected boolean _verbose;
-
- /** Flag used to indicate if this is a point to point or pub/sub ping client. */
- protected boolean _isPubSub;
-
- /** Flag used to indicate if the destinations should be unique client. */
- protected boolean _isUnique;
-
- /** Flag used to indicate that durable destination should be used. */
- protected boolean _isDurable;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */
- protected boolean _failBeforeCommit;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */
- protected boolean _failAfterCommit;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */
- protected boolean _failBeforeSend;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */
- protected boolean _failAfterSend;
-
- /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */
- protected boolean _failOnce;
-
- /** Holds the number of sends that should be performed in every transaction when using transactions. */
- protected int _txBatchSize;
-
- /** Holds the number of destinations to ping. */
- protected int _noOfDestinations;
-
- /** Holds the number of consumers per destination. */
- protected int _noOfConsumers;
-
- private int[] _consumerBatchCounts;
-
- /** Holds the maximum send rate in herz. */
- protected int _rate;
-
- /**
- * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended
- * if this limit is breached.
- */
- protected int _maxPendingSize;
-
- /**
- * Holds the number of messages to send during the setup phase, before the clients start consuming.
- */
- private Integer _preFill;
-
- /**
- * Holds the time in ms to wait after preFilling before starting thet test.
- */
- private Long _delayBeforeConsume;
-
- /**
- * Holds a boolean value of wither this test should just consume, i.e. skips
- * sending messages, but still expects to receive the specified number.
- */
- private boolean _consumeOnly;
-
- /**
- * Holds a boolean value of wither this test should just send, i.e. skips
- * consuming messages, but still creates clients just doesn't start them.
- */
- private boolean _sendOnly;
-
-
- /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */
- private static AtomicLong _correlationIdGenerator = new AtomicLong(0L);
-
- /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */
- private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0);
-
- /** Holds this instances unique id. */
- private int instanceId;
-
- /**
- * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple
- * ping producers on the same JVM.
- */
- private static Map<String, PerCorrelationId> perCorrelationIds =
- Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
-
- /** A convenient formatter to use when time stamping output. */
- protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
-
- /** Holds the connection for the message producer. */
- protected Connection _connection;
-
- /** Holds the consumer connections. */
- protected Connection[] _consumerConnection;
-
- /** Holds the controlSession on which ping replies are received. */
- protected Session[] _consumerSession;
-
- /** Holds the producer controlSession, needed to create ping messages. */
- protected Session _producerSession;
-
- /** Holds the destination where the response messages will arrive. */
- protected Destination _replyDestination;
-
- /** Holds the set of destinations that this ping producer pings. */
- protected List<Destination> _pingDestinations;
-
- /** Used to restrict the sending rate to a specified limit. */
- protected Throttle _rateLimiter;
-
- /** Holds a message listener that this message listener chains all its messages to. */
- protected ChainedMessageListener _chainedMessageListener = null;
-
- /**
- * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when
- * creating multiple ping producers in the same JVM.
- */
- protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger();
-
- /**
- * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers
- * on the same JVM using this id generator will allow them to ping on the same queues.
- */
- protected AtomicInteger _queueSharedID = new AtomicInteger();
-
- /** Used to tell the ping loop when to terminate, it only runs while this is true. */
- protected boolean _publish = true;
-
- /** Holds the message producer to send the pings through. */
- protected MessageProducer _producer;
-
- /** Holds the message consumer to receive the ping replies through. */
- protected MessageConsumer[] _consumer;
-
- /** The prompt to display when asking the user to kill the broker for failover testing. */
- private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return.";
-
- /** Holds the name for this test client to be identified to the broker with. */
- private String _clientID;
-
- /** Keeps count of the total messages sent purely for debugging purposes. */
- private static AtomicInteger numSent = new AtomicInteger();
-
- /**
- * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected
- * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a
- * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an
- * equal chance to produce messages.
- */
- static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true);
-
- /** Keeps a count of the number of message currently sent but not received. */
- static AtomicInteger _unreceived = new AtomicInteger(0);
-
- /**
- * Creates a ping producer with the specified parameters, of which there are many. See the class level comments
- * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on
- * it, to send and recieve its pings and replies on.
- *
- * @param overrides Properties containing any desired overrides to the defaults.
- *
- * @throws Exception Any exceptions are allowed to fall through.
- */
- public PingPongProducer(Properties overrides) throws Exception
- {
- // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called");
- instanceId = _instanceIdGenerator.getAndIncrement();
-
- // Create a set of parsed properties from the defaults overriden by the passed in values.
- ParsedProperties properties = new ParsedProperties(defaults);
- properties.putAll(overrides);
-
- // Extract the configuration properties to set the pinger up with.
- _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME);
- _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME);
- _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME);
- _brokerDetails = properties.getProperty(BROKER_PROPNAME);
- _username = properties.getProperty(USERNAME_PROPNAME);
- _password = properties.getProperty(PASSWORD_PROPNAME);
- _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME);
- _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME);
- _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME);
- _selector = properties.getProperty(SELECTOR_PROPNAME);
- _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME);
- _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME);
- _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME);
- _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME);
- _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME);
- _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME);
- _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME);
- _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME);
- _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME);
- _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME);
- _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME);
- _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME);
- _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME);
- _consumerBatchCounts = new int[_noOfConsumers];
- _rate = properties.getPropertyAsInteger(RATE_PROPNAME);
- _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME);
- _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME);
- _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME);
- _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME);
- _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME);
- _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME);
- _preFill = properties.getPropertyAsInteger(PREFILL_PROPNAME);
- _delayBeforeConsume = properties.getPropertyAsLong(DELAY_BEFORE_CONSUME_PROPNAME);
- _consumeOnly = properties.getPropertyAsBoolean(CONSUME_ONLY_PROPNAME);
- _sendOnly = properties.getPropertyAsBoolean(SEND_ONLY_PROPNAME);
-
- // Check that one or more destinations were specified.
- if (_noOfDestinations < 1)
- {
- throw new IllegalArgumentException("There must be at least one destination.");
- }
-
- // Set up a throttle to control the send rate, if a rate > 0 is specified.
- if (_rate > 0)
- {
- _rateLimiter = new BatchedThrottle();
- _rateLimiter.setRate(_rate);
- }
-
- // Create the connection and message producers/consumers.
- // establishConnection(true, true);
- }
-
- /**
- * Establishes a connection to the broker and creates message consumers and producers based on the parameters
- * that this ping client was created with.
- *
- * @param producer Flag to indicate whether or not the producer should be set up.
- * @param consumer Flag to indicate whether or not the consumers should be set up.
- *
- * @throws Exception Any exceptions are allowed to fall through.
- */
- public void establishConnection(boolean producer, boolean consumer) throws Exception
- {
- // log.debug("public void establishConnection(): called");
-
- // Generate a unique identifying name for this client, based on it ip address and the current time.
- InetAddress address = InetAddress.getLocalHost();
- // _clientID = address.getHostName() + System.currentTimeMillis();
- _clientID = "perftest_" + instanceId;
-
- // Create a connection to the broker.
- createConnection(_clientID);
-
- // Create transactional or non-transactional sessions, based on the command line arguments.
- _producerSession = _connection.createSession(_transacted, _ackMode);
-
- _consumerSession = new Session[_noOfConsumers];
-
- for (int i = 0; i < _noOfConsumers; i++)
- {
- _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode);
- }
-
- // Create the destinations to send pings to and receive replies from.
- if (_noOfConsumers > 0)
- {
- _replyDestination = _consumerSession[0].createTemporaryQueue();
- }
- createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable);
-
- // Create the message producer only if instructed to.
- if (producer)
- {
- createProducer();
- }
-
- // Create the message consumer only if instructed to.
- if (consumer)
- {
- createReplyConsumers(getReplyDestinations(), _selector);
- }
- }
-
- /**
- * Establishes a connection to the broker, based on the configuration parameters that this ping client was
- * created with.
- *
- * @param clientID The clients identifier.
- *
- * @throws JMSException Underlying exceptions allowed to fall through.
- * @throws NamingException Underlying exceptions allowed to fall through.
- * @throws IOException Underlying exceptions allowed to fall through.
- */
- protected void createConnection(String clientID) throws JMSException, NamingException, IOException
- {
- // _log.debug("protected void createConnection(String clientID = " + clientID + "): called");
-
- // _log.debug("Creating a connection for the message producer.");
- File propsFile = new File(_fileProperties);
- InputStream is = new FileInputStream(propsFile);
- Properties properties = new Properties();
- properties.load(is);
-
- Context context = new InitialContext(properties);
- ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName);
- _connection = factory.createConnection(_username, _password);
-
- if (_overrideClientId)
- {
- _connection.setClientID(clientID);
- }
-
- // _log.debug("Creating " + _noOfConsumers + " connections for the consumers.");
-
- _consumerConnection = new Connection[_noOfConsumers];
-
- for (int i = 0; i < _noOfConsumers; i++)
- {
- _consumerConnection[i] = factory.createConnection(_username, _password);
- // _consumerConnection[i].setClientID(clientID);
- }
- }
-
- /**
- * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs
- * to be started to bounce the pings back again.
- *
- * @param args The command line arguments.
- */
- public static void main(String[] args)
- {
- try
- {
- Properties options =
- CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties());
-
- // Create a ping producer overriding its defaults with all options passed on the command line.
- PingPongProducer pingProducer = new PingPongProducer(options);
- pingProducer.establishConnection(true, true);
-
- // Start the ping producers dispatch thread running.
- pingProducer._connection.start();
-
- // Create a shutdown hook to terminate the ping-pong producer.
- Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook());
-
- // Ensure that the ping pong producer is registered to listen for exceptions on the connection too.
- pingProducer._connection.setExceptionListener(pingProducer);
-
- // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception.
- Thread pingThread = new Thread(pingProducer);
- pingThread.run();
- pingThread.join();
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- log.error("Top level handler caught execption.", e);
- System.exit(1);
- }
- }
-
- /**
- * Convenience method for a short pause.
- *
- * @param sleepTime The time in milliseconds to pause for.
- */
- public static void pause(long sleepTime)
- {
- if (sleepTime > 0)
- {
- try
- {
- Thread.sleep(sleepTime);
- }
- catch (InterruptedException ie)
- { }
- }
- }
-
- /**
- * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to
- * destination of this pinger.
- *
- * @return The single reply to destination of this pinger, wrapped in a list.
- */
- public List<Destination> getReplyDestinations()
- {
- // log.debug("public List<Destination> getReplyDestinations(): called");
-
- List<Destination> replyDestinations = new ArrayList<Destination>();
- replyDestinations.add(_replyDestination);
-
- // log.debug("replyDestinations = " + replyDestinations);
-
- return replyDestinations;
- }
-
- /**
- * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery
- * flag is set accoring the ping producer creation options.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- public void createProducer() throws JMSException
- {
- // log.debug("public void createProducer(): called");
-
- _producer = (MessageProducer) _producerSession.createProducer(null);
- _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
-
- // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages.");
- }
-
- /**
- * Creates consumers for the specified number of destinations. The destinations themselves are also created by this
- * method.
- *
- * @param noOfDestinations The number of destinations to create consumers for.
- * @param selector The message selector to filter the consumers with.
- * @param rootName The root of the name, or actual name if only one is being created.
- * @param unique <tt>true</tt> to make the destinations unique to this pinger, <tt>false</tt> to share the
- * numbering with all pingers on the same JVM.
- * @param durable If the destinations are durable topics.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique,
- boolean durable) throws JMSException
- {
- /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = "
- + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = "
- + durable + "): called");*/
-
- _pingDestinations = new ArrayList<Destination>();
-
- // Create the desired number of ping destinations and consumers for them.
- // log.debug("Creating " + noOfDestinations + " destinations to ping.");
-
- for (int i = 0; i < noOfDestinations; i++)
- {
- Destination destination;
- String id;
-
- // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag.
- if (unique)
- {
- // log.debug("Creating unique destinations.");
- id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID();
- }
- else
- {
- // log.debug("Creating shared destinations.");
- id = "_" + _queueSharedID.incrementAndGet();
- }
-
- // Check if this is a pub/sub pinger, in which case create topics.
- if (_isPubSub)
- {
- destination = _producerSession.createTopic(rootName + id);
- // log.debug("Created non-durable topic " + destination);
-
- if (durable)
- {
- _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID());
- }
- }
- // Otherwise this is a p2p pinger, in which case create queues.
- else
- {
- destination = _producerSession.createQueue(rootName + id + _queueNamePostfix);
- // log.debug("Created queue " + destination);
- }
-
- // Keep the destination.
- _pingDestinations.add(destination);
- }
- }
-
- /**
- * Creates consumers for the specified destinations and registers this pinger to listen to their messages.
- *
- * @param destinations The destinations to listen to.
- * @param selector A selector to filter the messages with.
- *
- * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through.
- */
- public void createReplyConsumers(Collection<Destination> destinations, String selector) throws JMSException
- {
- /*log.debug("public void createReplyConsumers(Collection<Destination> destinations = " + destinations
- + ", String selector = " + selector + "): called");*/
-
- log.debug("There are " + destinations.size() + " destinations.");
- log.debug("Creating " + _noOfConsumers + " consumers on each destination.");
- log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers));
-
- for (Destination destination : destinations)
- {
- _consumer = new MessageConsumer[_noOfConsumers];
-
- // If we don't have consumers then ensure we have created the
- // destination.
- if (_noOfConsumers == 0)
- {
- _producerSession.createConsumer(destination, selector,
- NO_LOCAL_DEFAULT).close();
- }
-
- for (int i = 0; i < _noOfConsumers; i++)
- {
- // Create a consumer for the destination and set this pinger to listen to its messages.
- _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT);
-
- final int consumerNo = i;
-
- _consumer[i].setMessageListener(new MessageListener()
- {
- public void onMessage(Message message)
- {
- onMessageWithConsumerNo(message, consumerNo);
- }
- });
-
- log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination);
- }
- }
- }
-
- /**
- * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a
- * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the
- * replies map.
- *
- * @param message The received message.
- * @param consumerNo The consumer number within this test pinger instance.
- */
- public void onMessageWithConsumerNo(Message message, int consumerNo)
- {
- // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called");
- try
- {
- long now = System.nanoTime();
- long timestamp = getTimestamp(message);
- long pingTime = now - timestamp;
-
- // NDC.push("id" + instanceId + "/cons" + consumerNo);
-
- // Extract the messages correlation id.
- String correlationID = message.getJMSCorrelationID();
- // log.debug("correlationID = " + correlationID);
-
- // int num = message.getIntProperty("MSG_NUM");
- // log.info("Message " + num + " received.");
-
- boolean isRedelivered = message.getJMSRedelivered();
- // log.debug("isRedelivered = " + isRedelivered);
-
- if (!isRedelivered)
- {
- // Countdown on the traffic light if there is one for the matching correlation id.
- PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID);
-
- if (perCorrelationId != null)
- {
- CountDownLatch trafficLight = perCorrelationId.trafficLight;
-
- // Restart the timeout timer on every message.
- perCorrelationId.timeOutStart = System.nanoTime();
-
- // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID);
-
- // Release waiting senders if there are some and using maxPending limit.
- if ((_maxPendingSize > 0))
- {
- // Decrement the count of sent but not yet received messages.
- int unreceived = _unreceived.decrementAndGet();
- int unreceivedSize =
- (unreceived * ((_messageSize == 0) ? 1 : _messageSize))
- / (_isPubSub ? getConsumersPerDestination() : 1);
-
- // log.debug("unreceived = " + unreceived);
- // log.debug("unreceivedSize = " + unreceivedSize);
-
- // synchronized (_sendPauseMonitor)
- // {
- if (unreceivedSize < _maxPendingSize)
- {
- _sendPauseMonitor.poll();
- }
- // }
- }
-
- // Decrement the countdown latch. Before this point, it is possible that two threads might enter this
- // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block
- // ensures that each thread will get a unique value for the remaining messages.
- long trueCount;
- long remainingCount;
-
- synchronized (trafficLight)
- {
- trafficLight.countDown();
-
- trueCount = trafficLight.getCount();
- remainingCount = trueCount - 1;
-
- if (++_consumerBatchCounts[consumerNo] == _txBatchSize)
- {
- _consumerBatchCounts[consumerNo] = 0;
- if (_consAckMode == 2)
- {
- // log.debug("Doing client ack for consumer " + consumerNo + ".");
- message.acknowledge();
- }
- else
- {
- // log.debug("Trying commit for consumer " + consumerNo + ".");
- commitTx(_consumerSession[consumerNo]);
- // log.info("Tx committed on consumer " + consumerNo);
- }
- }
-
- // Forward the message and remaining count to any interested chained message listener.
- if (_chainedMessageListener != null)
- {
- _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime);
- }
-
- // Check if this is the last message, in which case release any waiting producers. This is done
- // after the transaction has been committed and any listeners notified.
- if (trueCount == 1)
- {
- trafficLight.countDown();
- }
- }
- }
- else
- {
- log.warn(consumerNo + " Got unexpected message with correlationId: " + correlationID);
- log.warn(consumerNo + " Map contains:" + perCorrelationIds.entrySet());
- }
- }
- else
- {
- log.warn("Got redelivered message, ignoring.");
- }
- }
- catch (Exception e)
- {
- log.warn("There was a Exception: " + e.getMessage(), e);
- }
- finally
- {
- // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending");
- // NDC.clear();
- }
- }
-
- public void setupCorrelationID(String correlationId, int expectedCount)
- {
- PerCorrelationId perCorrelationId = new PerCorrelationId();
-
- // Create a count down latch to count the number of replies with. This is created before the messages are
- // sent so that the replies cannot be received before the count down is created.
- // One is added to this, so that the last reply becomes a special case. The special case is that the
- // chained message listener must be called before this sender can be unblocked, but that decrementing the
- // countdown needs to be done before the chained listener can be called.
- perCorrelationId.trafficLight = new CountDownLatch(expectedCount + 1);
-
- perCorrelationIds.put(correlationId, perCorrelationId);
- }
-
-
- /**
- * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out
- * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify
- * the correlation id.
- *
- * Can be augmented through a pre-fill property (PingPongProducer.PREFILL_PROPNAME) that will populate the destination
- * with a set number of messages so the total pings sent and therefore expected will be PREFILL + numPings.
- *
- * If pre-fill is specified then the consumers will start paused to allow the prefilling to occur.
- *
- * @param message The message to send. If this is null, one is generated.
- * @param numPings The number of ping messages to send.
- * @param timeout The timeout in milliseconds.
- * @param messageCorrelationId The message correlation id. If this is null, one is generated.
- *
- * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait
- * for all prematurely. If we are running in noConsumer=0 so send only mode then it will return the no msgs sent.
- *
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- * @throws InterruptedException When interrupted by a timeout
- */
- public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId)
- throws JMSException, InterruptedException
- {
- return pingAndWaitForReply(message, numPings, 0, timeout, messageCorrelationId);
- }
-
- public int pingAndWaitForReply(Message message, int numPings, int preFill, long timeout, String messageCorrelationId)
- throws JMSException, InterruptedException
- {
- /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = "
- + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/
-
- int totalPingsRequested = numPings + preFill;
-
- // Generate a unique correlation id to put on the messages before sending them, if one was not specified.
- if (messageCorrelationId == null)
- {
- messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet());
-
- setupCorrelationID(messageCorrelationId, getExpectedNumPings(totalPingsRequested));
- }
-
- try
- {
- // NDC.push("prod");
-
- PerCorrelationId perCorrelationId = perCorrelationIds.get(messageCorrelationId);
-
- // Set up the current time as the start time for pinging on the correlation id. This is used to determine
- // timeouts.
- perCorrelationId.timeOutStart = System.nanoTime();
-
- // Send the specifed number of messages for this test
- pingNoWaitForReply(message, numPings, messageCorrelationId);
-
- boolean timedOut;
- boolean allMessagesReceived;
- int numReplies;
-
- // We don't have a consumer so don't try and wait for the messages.
- // this does mean that if the producerSession is !TXed then we may
- // get to exit before all msgs have been received.
- //
- // Return the number of requested messages, this will let the test
- // report a pass.
- if (_noOfConsumers == 0 || _sendOnly)
- {
- return getExpectedNumPings(totalPingsRequested);
- }
-
- do
- {
- // Block the current thread until replies to all the messages are received, or it times out.
- perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS);
-
- // Work out how many replies were receieved.
- numReplies = getExpectedNumPings(totalPingsRequested) - (int) perCorrelationId.trafficLight.getCount();
-
- allMessagesReceived = numReplies == getExpectedNumPings(totalPingsRequested);
-
- // log.debug("numReplies = " + numReplies);
- // log.debug("allMessagesReceived = " + allMessagesReceived);
-
- // Recheck the timeout condition.
- long now = System.nanoTime();
- long lastMessageReceievedAt = perCorrelationId.timeOutStart;
- timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000);
-
- // log.debug("now = " + now);
- // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt);
- }
- while (!timedOut && !allMessagesReceived);
-
- if ((numReplies < getExpectedNumPings(totalPingsRequested)) && _verbose)
- {
- log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId);
- }
- else if (_verbose)
- {
- log.info("Got all replies on id, " + messageCorrelationId);
- }
-
- // commitTx(_consumerSession);
-
- // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending");
-
- return numReplies;
- }
- // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived,
- // so will be a memory leak if this is not done.
- finally
- {
- // NDC.pop();
- perCorrelationIds.remove(messageCorrelationId);
- }
- }
-
- /**
- * Sends the specified number of ping messages and does not wait for correlating replies.
- *
- * @param message The message to send.
- * @param numPings The number of pings to send.
- * @param messageCorrelationId A correlation id to place on all messages sent.
- *
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- */
- public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException
- {
- /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings
- + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/
-
- // If we are runnning a consumeOnly test then don't send any messages
- if (_consumeOnly)
- {
- return;
- }
-
- if (message == null)
- {
- message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent);
- }
-
- message.setJMSCorrelationID(messageCorrelationId);
-
- // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the
- // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is
- // needed.
- boolean committed = false;
-
- // Send all of the ping messages.
- for (int i = 0; i < numPings; i++)
- {
- // Re-timestamp the message.
- // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
-
- // Send the message, passing in the message count.
- committed = sendMessage(i, message);
-
- // Spew out per message timings on every message sonly in verbose mode.
- /*if (_verbose)
- {
- log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId);
- }*/
- }
-
- // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages.
- if (!committed)
- {
- commitTx(_producerSession);
- }
- }
-
- /**
- * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of
- * messages sent so far must be specified and is used to round robin the ping destinations (where there are more
- * than one), and to determine if the transaction batch size has been reached and the sent messages should be
- * committed.
- *
- * @param i The count of messages sent so far in a loop of multiple calls to this send method.
- * @param message The message to send.
- *
- * @return <tt>true</tt> if the messages were committed, <tt>false</tt> otherwise.
- *
- * @throws JMSException All underlyiung JMSExceptions are allowed to fall through.
- */
- protected boolean sendMessage(int i, Message message) throws JMSException
- {
- try
- {
- NDC.push("id" + instanceId + "/prod");
-
- // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called");
- // log.debug("_txBatchSize = " + _txBatchSize);
-
- // Round robin the destinations as the messages are sent.
- Destination destination = _pingDestinations.get(i % _pingDestinations.size());
-
- // Prompt the user to kill the broker when doing failover testing.
- _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend);
-
- // Get the test setup for the correlation id.
- String correlationID = message.getJMSCorrelationID();
- PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID);
-
- // If necessary, wait until the max pending message size comes within its limit.
- if (_maxPendingSize > 0)
- {
- synchronized (_sendPauseMonitor)
- {
- // Used to keep track of the number of times that send has to wait.
- int numWaits = 0;
-
- // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with
- // the test timeout.
- int waitLimit = (int) (TIMEOUT_DEFAULT / 10000);
-
- while (true)
- {
- // Get the size estimate of sent but not yet received messages.
- int unreceived = _unreceived.get();
- int unreceivedSize =
- (unreceived * ((_messageSize == 0) ? 1 : _messageSize))
- / (_isPubSub ? getConsumersPerDestination() : 1);
-
- // log.debug("unreceived = " + unreceived);
- // log.debug("unreceivedSize = " + unreceivedSize);
- // log.debug("_maxPendingSize = " + _maxPendingSize);
-
- if (unreceivedSize > _maxPendingSize)
- {
- // log.debug("unreceived size estimate over limit = " + unreceivedSize);
-
- // Fail the test if the send has had to wait more than the maximum allowed number of times.
- if (numWaits > waitLimit)
- {
- String errorMessage =
- "Send has had to wait for the unreceivedSize (" + unreceivedSize
- + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit
- + " times.";
- log.warn(errorMessage);
- throw new RuntimeException(errorMessage);
- }
-
- // Wait on the send pause barrier for the limit to be re-established.
- try
- {
- long start = System.nanoTime();
- // _sendPauseMonitor.wait(10000);
- _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS);
- long end = System.nanoTime();
-
- // Count the wait only if it was for > 99% of the requested wait time.
- if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99)
- {
- numWaits++;
- }
- }
- catch (InterruptedException e)
- {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- }
- else
- {
- break;
- }
- }
- }
- }
-
- // Send the message either to its round robin destination, or its default destination.
- // int num = numSent.incrementAndGet();
- // message.setIntProperty("MSG_NUM", num);
- setTimestamp(message);
-
- if (destination == null)
- {
- _producer.send(message);
- }
- else
- {
- _producer.send(destination, message);
- }
-
- // Increase the unreceived size, this may actually happen after the message is received.
- // The unreceived size is incremented by the number of consumers that will get a copy of the message,
- // in pub/sub mode.
- if (_maxPendingSize > 0)
- {
- int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1);
- // log.debug("newUnreceivedCount = " + newUnreceivedCount);
- }
-
- // Apply message rate throttling if a rate limit has been set up.
- if (_rateLimiter != null)
- {
- _rateLimiter.throttle();
- }
-
- // Call commit every time the commit batch size is reached.
- boolean committed = false;
-
- // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent.
- if (((i + 1) % _txBatchSize) == 0)
- {
- // log.debug("Trying commit on producer session.");
- committed = commitTx(_producerSession);
- }
-
- return committed;
- }
- finally
- {
- NDC.clear();
- }
- }
-
- /**
- * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the
- * test that the failure has occurred, before the method returns.
- *
- * @param failFlag The fail flag to test.
- *
- * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only
- * used once, then reset.
- */
- private boolean waitForUserToPromptOnFailure(boolean failFlag)
- {
- if (failFlag)
- {
- if (_failOnce)
- {
- failFlag = false;
- }
-
- // log.debug("Failing Before Send");
- waitForUser(KILL_BROKER_PROMPT);
- }
-
- return failFlag;
- }
-
- /**
- * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch
- * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will
- * terminate the pinger.
- */
- public void pingLoop()
- {
- try
- {
- // Generate a sample message and time stamp it.
- Message msg = getTestMessage(_replyDestination, _messageSize, _persistent);
- // setTimestamp(msg);
-
- // Send the message and wait for a reply.
- pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null);
- }
- catch (JMSException e)
- {
- _publish = false;
- // log.debug("There was a JMSException: " + e.getMessage(), e);
- }
- catch (InterruptedException e)
- {
- _publish = false;
- // log.debug("There was an interruption: " + e.getMessage(), e);
- }
- }
-
- /**
- * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set
- * here.
- *
- * @param messageListener The chained message listener.
- */
- public void setChainedMessageListener(ChainedMessageListener messageListener)
- {
- _chainedMessageListener = messageListener;
- }
-
- /** Removes any chained message listeners from this pinger. */
- public void removeChainedMessageListener()
- {
- _chainedMessageListener = null;
- }
-
- /**
- * Generates a test message of the specified size, with the specified reply-to destination and persistence flag.
- *
- * @param replyQueue The reply-to destination for the message.
- * @param messageSize The desired size of the message in bytes.
- * @param persistent <tt>true</tt> if the message should use persistent delivery, <tt>false</tt> otherwise.
- *
- * @return A freshly generated test message.
- *
- * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through.
- */
- public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException
- {
- // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent);
- return TestUtils.createTestMessageOfSize(_producerSession, messageSize);
- }
-
- /**
- * Sets the current time in nanoseconds as the timestamp on the message.
- *
- * @param msg The message to timestamp.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- protected void setTimestamp(Message msg) throws JMSException
- {
- /*if (((AMQSession)_producerSession).isStrictAMQP())
- {
- ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime());
- }
- else
- {*/
- msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
- // }
- }
-
- /**
- * Extracts the nanosecond timestamp from a message.
- *
- * @param msg The message to extract the time stamp from.
- *
- * @return The timestamp in nanos.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- protected long getTimestamp(Message msg) throws JMSException
- {
- /*if (((AMQSession)_producerSession).isStrictAMQP())
- {
- Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME));
-
- return (value == null) ? 0L : value;
- }
- else
- {*/
- return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME);
- // }
- }
-
- /**
- * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag
- * has been cleared.
- */
- public void stop()
- {
- _publish = false;
- }
-
- /**
- * Starts the producer and consumer connections.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- public void start() throws JMSException
- {
- // log.debug("public void start(): called");
-
- _connection.start();
- // log.debug("Producer started.");
-
- for (int i = 0; i < _noOfConsumers; i++)
- {
- _consumerConnection[i].start();
- // log.debug("Consumer " + i + " started.");
- }
- }
-
- /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */
- public void run()
- {
- // Keep running until the publish flag is cleared.
- while (_publish)
- {
- pingLoop();
- }
- }
-
- /**
- * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the
- * connection, this clears the publish flag which in turn will halt the ping loop.
- *
- * @param e The exception that triggered this callback method.
- */
- public void onException(JMSException e)
- {
- // log.debug("public void onException(JMSException e = " + e + "): called", e);
- _publish = false;
- }
-
- /**
- * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered
- * with the runtime system as a shutdown hook.
- *
- * @return A shutdown hook for the ping loop.
- */
- public Thread getShutdownHook()
- {
- return new Thread(new Runnable()
- {
- public void run()
- {
- stop();
- }
- });
- }
-
- /**
- * Closes all of the producer and consumer connections.
- *
- * @throws JMSException All JMSException are allowed to fall through.
- */
- public void close() throws JMSException
- {
- // log.debug("public void close(): called");
-
- try
- {
- if (_connection != null)
- {
- // log.debug("Before close producer connection.");
- _connection.close();
- // log.debug("Closed producer connection.");
- }
-
- for (int i = 0; i < _noOfConsumers; i++)
- {
- if (_consumerConnection[i] != null)
- {
- // log.debug("Before close consumer connection " + i + ".");
- _consumerConnection[i].close();
- // log.debug("Closed consumer connection " + i + ".");
- }
- }
- }
- finally
- {
- _connection = null;
- _producerSession = null;
- _consumerSession = null;
- _consumerConnection = null;
- _producer = null;
- _consumer = null;
- _pingDestinations = null;
- _replyDestination = null;
- }
- }
-
- /**
- * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a
- * transactional controlSession, this method does nothing (unless the failover after send flag is set).
- *
- * <p/>If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is
- * applied. This flag applies whether the pinger is transactional or not.
- *
- * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit
- * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the
- * commit is applied. These flags will only apply if using a transactional pinger.
- *
- * @param session The controlSession to commit
- *
- * @return <tt>true</tt> if the controlSession was committed, <tt>false</tt> if it was not.
- *
- * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
- *
- * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit
- * method, because commits only apply to transactional pingers, but fail after send applied to transactional and
- * non-transactional alike.
- */
- protected boolean commitTx(Session session) throws JMSException
- {
- // log.debug("protected void commitTx(Session session): called");
-
- boolean committed = false;
-
- _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend);
-
- if (session.getTransacted())
- {
- // log.debug("Session is transacted.");
-
- try
- {
- _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit);
-
- long start = System.nanoTime();
- session.commit();
- committed = true;
- // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms");
-
- _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit);
-
- // log.debug("Session Commited.");
- }
- catch (JMSException e)
- {
- // log.debug("JMSException on commit:" + e.getMessage(), e);
-
- try
- {
- session.rollback();
- // log.debug("Message rolled back.");
- }
- catch (JMSException jmse)
- {
- // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse);
-
- // Both commit and rollback failed. Throw the rollback exception.
- throw jmse;
- }
- }
- }
-
- return committed;
- }
-
- /**
- * Outputs a prompt to the console and waits for the user to press return.
- *
- * @param prompt The prompt to display on the console.
- */
- public void waitForUser(String prompt)
- {
- System.out.println(prompt);
-
- try
- {
- System.in.read();
- }
- catch (IOException e)
- {
- // Ignored.
- }
-
- System.out.println("Continuing.");
- }
-
- /**
- * Gets the number of consumers that are listening to each destination in the test.
- *
- * @return int The number of consumers subscribing to each topic.
- */
- public int getConsumersPerDestination()
- {
- return _noOfConsumers;
- }
-
- /**
- * Calculates how many pings are expected to be received for the given number sent.
- *
- * Note : that if you have set noConsumers to 0 then this will also return 0
- * in the case of PubSub testing. This is correct as without consumers there
- * will be no-one to receive the sent messages so they will be unable to respond.
- *
- * @param numpings The number of pings that will be sent.
- *
- * @return The number that should be received, for the test to pass.
- */
- public int getExpectedNumPings(int numpings)
- {
- // Wow, I'm freaking sorry about this return here...
- return ((_failAfterSend || _failBeforeCommit) ? numpings - 1: numpings) *
- (_isPubSub ? getConsumersPerDestination() : 1);
- }
-
- /**
- * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link
- * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link
- * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of
- * messages with that correlation id.
- *
- * <p/>Provided only one pinger is producing messages with that correlation id, the chained listener will always be
- * given unique message counts. It will always be called while the producer waiting for all messages to arrive is
- * still blocked.
- */
- public static interface ChainedMessageListener
- {
- /**
- * Notifies interested listeners about message arrival and important test stats, the number of messages
- * remaining in the test, and the messages send timestamp.
- *
- * @param message The newly arrived message.
- * @param remainingCount The number of messages left to complete the test.
- * @param latency The nanosecond latency of the message.
- *
- * @throws JMSException Any JMS exceptions is allowed to fall through.
- */
- public void onMessage(Message message, int remainingCount, long latency) throws JMSException;
- }
-
- /**
- * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be
- * added to this: read/write lock to make onMessage more concurrent as described in class header comment.
- */
- protected static class PerCorrelationId
- {
- /** Holds a countdown on number of expected messages. */
- CountDownLatch trafficLight;
-
- /** Holds the last timestamp that the timeout was reset to. */
- Long timeOutStart;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java
deleted file mode 100644
index 009254c612..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.requestreply;
-
-import junit.framework.Assert;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.junit.extensions.AsymptoticTestCase;
-import org.apache.qpid.junit.extensions.util.ParsedProperties;
-import org.apache.qpid.junit.extensions.util.TestContextProperties;
-
-import javax.jms.*;
-
-/**
- * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run
- * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from
- * a producer to a conumer, then the consumer replies to the message on a temporary queue.
- *
- * <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of the number
- * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled
- * up using a suitable JUnit test runner. See {@link org.apache.qpid.junit.extensions.TKTestRunner} for more
- * information on how to do this.
- *
- * <p/>The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a
- * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads
- * gets its own connection/producer/consumer, this is only re-established if the connection is lost.
- *
- * <p/>The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that
- * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come
- * back on the temporary queue.
- *
- * <p/>Configurable test properties: message size, transacted or not, persistent or not. Broker connection details.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- */
-public class PingPongTestPerf extends AsymptoticTestCase
-{
- private static Logger _logger = Logger.getLogger(PingPongTestPerf.class);
-
- /** Thread local to hold the per-thread test setup fields. */
- ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
-
- // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in
- // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner
- // of the test parameters to log with the results. It also providers some basic type parsing convenience methods.
- // private Properties testParameters = System.getProperties();
- private ParsedProperties testParameters =
- TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/);
-
- public PingPongTestPerf(String name)
- {
- super(name);
-
- _logger.debug(testParameters);
-
- // Sets up the test parameters with defaults.
- /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME,
- Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME,
- Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT));
- testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME,
- PingPongProducer.PING_QUEUE_NAME_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME,
- Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME,
- Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME,
- Boolean.toString(PingPongProducer.VERBOSE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME,
- Boolean.toString(PingPongProducer.PUBSUB_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME,
- Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME,
- Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME,
- PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME,
- PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME,
- PingPongProducer.FAIL_AFTER_SEND_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME,
- PingPongProducer.FAIL_BEFORE_SEND_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT);
- testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME,
- Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME,
- Integer.toString(PingPongProducer.ACK_MODE_DEFAULT));
- testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME,
- PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/
- }
-
- /**
- * Compile all the tests into a test suite.
- */
- public static Test suite()
- {
- // Build a new test suite
- TestSuite suite = new TestSuite("Ping-Pong Performance Tests");
-
- // Run performance tests in read committed mode.
- suite.addTest(new PingPongTestPerf("testPingPongOk"));
-
- return suite;
- }
-
- private static void setSystemPropertyIfNull(String propName, String propValue)
- {
- if (System.getProperty(propName) == null)
- {
- System.setProperty(propName, propValue);
- }
- }
-
- public void testPingPongOk(int numPings) throws Exception
- {
- // Get the per thread test setup to run the test through.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- // Generate a sample message. This message is already time stamped and has its reply-to destination set.
- Message msg =
- perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0),
- testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
- testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
-
- // Send the message and wait for a reply.
- int numReplies =
- perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null);
-
- // Fail the test if the timeout was exceeded.
- if (numReplies != numPings)
- {
- Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings);
- }
- }
-
- /**
- * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
- */
- public void threadSetUp()
- {
- try
- {
- PerThreadSetup perThreadSetup = new PerThreadSetup();
-
- // Extract the test set up paramaeters.
- String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME);
- String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME);
- String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME);
- String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME);
- String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME);
- boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME);
- boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME);
- String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME);
- boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME);
- boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME);
-
- synchronized (this)
- {
- // Establish a bounce back client on the ping queue to bounce back the pings.
- perThreadSetup._testPingBouncer =
- new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent,
- transacted, selector, verbose, pubsub);
-
- // Start the connections for client and producer running.
- perThreadSetup._testPingBouncer.getConnection().start();
-
- // Establish a ping-pong client on the ping queue to send the pings and receive replies with.
- perThreadSetup._testPingProducer = new PingPongProducer(testParameters);
- perThreadSetup._testPingProducer.establishConnection(true, true);
- perThreadSetup._testPingProducer.start();
- }
-
- // Attach the per-thread set to the thread.
- threadSetup.set(perThreadSetup);
- }
- catch (Exception e)
- {
- _logger.warn("There was an exception during per thread setup.", e);
- }
- }
-
- /**
- * Performs test fixture clean
- */
- public void threadTearDown()
- {
- _logger.debug("public void threadTearDown(): called");
-
- try
- {
- // Get the per thread test fixture.
- PerThreadSetup perThreadSetup = threadSetup.get();
-
- // Close the pingers so that it cleans up its connection cleanly.
- synchronized (this)
- {
- perThreadSetup._testPingProducer.close();
- // perThreadSetup._testPingBouncer.close();
- }
-
- // Ensure the per thread fixture is reclaimed.
- threadSetup.remove();
- }
- catch (JMSException e)
- {
- _logger.warn("There was an exception during per thread tear down.");
- }
- }
-
- protected static class PerThreadSetup
- {
- /**
- * Holds the test ping-pong producer.
- */
- private PingPongProducer _testPingProducer;
-
- /**
- * Holds the test ping client.
- */
- private PingPongBouncer _testPingBouncer;
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/java/perftests/src/main/java/org/apache/qpid/topic/Config.java
deleted file mode 100644
index d5c0979399..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/topic/Config.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.topic;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.config.ConnectorConfig;
-import org.apache.qpid.config.Connector;
-import org.apache.qpid.config.AbstractConfig;
-
-import javax.jms.Connection;
-
-public class Config extends AbstractConfig implements ConnectorConfig
-{
-
- private String host = "localhost";
- private int port = 5672;
- private String factory = null;
-
- private int payload = 256;
- private int messages = 1000;
- private int clients = 1;
- private int batch = 1;
- private long delay = 1;
- private int warmup;
- private int ackMode= AMQSession.NO_ACKNOWLEDGE;
- private String clientId;
- private String subscriptionId;
- private String selector;
- private String destinationName;
- private boolean persistent;
- private boolean transacted;
- private int destinationsCount;
- private int batchSize;
- private int rate;
- private boolean ispubsub;
- private long timeout;
-
- public Config()
- {
- }
-
- public int getAckMode()
- {
- return ackMode;
- }
-
- public void setPayload(int payload)
- {
- this.payload = payload;
- }
-
- public int getPayload()
- {
- return payload;
- }
-
- void setClients(int clients)
- {
- this.clients = clients;
- }
-
- int getClients()
- {
- return clients;
- }
-
- void setMessages(int messages)
- {
- this.messages = messages;
- }
-
- public int getMessages()
- {
- return messages;
- }
-
- public int getBatchSize()
- {
- return batchSize;
- }
-
- public int getRate()
- {
- return rate;
- }
-
- public int getDestinationsCount()
- {
- return destinationsCount;
- }
-
- public String getHost()
- {
- return host;
- }
-
- public void setHost(String host)
- {
- this.host = host;
- }
-
- public int getPort()
- {
- return port;
- }
-
- public String getFactory()
- {
- return factory;
- }
-
- public void setPort(int port)
- {
- this.port = port;
- }
-
- int getBatch()
- {
- return batch;
- }
-
- void setBatch(int batch)
- {
- this.batch = batch;
- }
-
- int getWarmup()
- {
- return warmup;
- }
-
- void setWarmup(int warmup)
- {
- this.warmup = warmup;
- }
-
- public long getDelay()
- {
- return delay;
- }
-
- public void setDelay(long delay)
- {
- this.delay = delay;
- }
-
- public long getTimeout()
- {
- return timeout;
- }
-
- public void setTimeout(long time)
- {
- this.timeout = time;
- }
-
- public String getClientId()
- {
- return clientId;
- }
-
- public String getSubscriptionId()
- {
- return subscriptionId;
- }
-
- public String getSelector()
- {
- return selector;
- }
-
- public String getDestination()
- {
- return destinationName;
- }
-
- public boolean usePersistentMessages()
- {
- return persistent;
- }
-
- public boolean isTransacted()
- {
- return transacted;
- }
-
- public boolean isPubSub()
- {
- return ispubsub;
- }
-
- public void setOption(String key, String value)
- {
- if("-host".equalsIgnoreCase(key))
- {
- setHost(value);
- }
- else if("-port".equalsIgnoreCase(key))
- {
- try
- {
- setPort(Integer.parseInt(value));
- }
- catch(NumberFormatException e)
- {
- throw new RuntimeException("Bad port number: " + value, e);
- }
- }
- else if("-payload".equalsIgnoreCase(key))
- {
- setPayload(parseInt("Bad payload size", value));
- }
- else if("-messages".equalsIgnoreCase(key))
- {
- setMessages(parseInt("Bad message count", value));
- }
- else if("-clients".equalsIgnoreCase(key))
- {
- setClients(parseInt("Bad client count", value));
- }
- else if("-batch".equalsIgnoreCase(key))
- {
- setBatch(parseInt("Bad batch count", value));
- }
- else if("-delay".equalsIgnoreCase(key))
- {
- setDelay(parseLong("Bad batch delay", value));
- }
- else if("-warmup".equalsIgnoreCase(key))
- {
- setWarmup(parseInt("Bad warmup count", value));
- }
- else if("-ack".equalsIgnoreCase(key))
- {
- ackMode = parseInt("Bad ack mode", value);
- }
- else if("-factory".equalsIgnoreCase(key))
- {
- factory = value;
- }
- else if("-clientId".equalsIgnoreCase(key))
- {
- clientId = value;
- }
- else if("-subscriptionId".equalsIgnoreCase(key))
- {
- subscriptionId = value;
- }
- else if("-persistent".equalsIgnoreCase(key))
- {
- persistent = "true".equalsIgnoreCase(value);
- }
- else if("-transacted".equalsIgnoreCase(key))
- {
- transacted = "true".equalsIgnoreCase(value);
- }
- else if ("-destinationscount".equalsIgnoreCase(key))
- {
- destinationsCount = parseInt("Bad destinations count", value);
- }
- else if ("-batchsize".equalsIgnoreCase(key))
- {
- batchSize = parseInt("Bad batch size", value);
- }
- else if ("-rate".equalsIgnoreCase(key))
- {
- rate = parseInt("MEssage rate", value);
- }
- else if("-pubsub".equalsIgnoreCase(key))
- {
- ispubsub = "true".equalsIgnoreCase(value);
- }
- else if("-selector".equalsIgnoreCase(key))
- {
- selector = value;
- }
- else if("-destinationname".equalsIgnoreCase(key))
- {
- destinationName = value;
- }
- else if("-timeout".equalsIgnoreCase(key))
- {
- setTimeout(parseLong("Bad timeout data", value));
- }
- else
- {
- System.out.println("Ignoring unrecognised option: " + key);
- }
- }
-
- static String getAckModeDescription(int ackMode)
- {
- switch(ackMode)
- {
- case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE";
- case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE";
- case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE";
- case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE";
- case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE";
- }
- return "AckMode=" + ackMode;
- }
-
- public Connection createConnection() throws Exception
- {
- return new Connector().createConnection(this);
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java
deleted file mode 100644
index 6dcea42bfe..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.topic;
-
-import java.util.Random;
-
-import javax.jms.*;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.exchange.ExchangeDefaults;
-
-/**
- * This class has not kept up to date with the topic_listener in the cpp tests. It should provide identical behaviour for
- * cross testing the java and cpp clients.
- *
- * <p/>How the cpp topic_publisher operates:
- * It publishes text messages to the default topic exchange, on virtual host "/test", on the topic "topic_control", for
- * the specified number of test messages to be sent.
- * It publishes a report request message (on same topic), with the header text field "TYPE", value "REPORT_REQUEST",
- * optionally within a transaction, and waits for the specified number of consumers to reply to this request. The
- * listeners should reply to this message on a queue named "response", on virtual host "/test", with some sort of message
- * about the number of messages received and how long it took, although the publisher never looks at the message content.
- * The publisher then send a message (on the same topic), with the header text field "TYPE", value "TERMINATION_REQUEST",
- * which the listener should close its connection and terminate upon receipt of.
- *
- * @todo I've added lots of field table types in the report message, just to check if the other end can decode them
- * correctly. Not really the right place to test this, so remove them from
- * {@link #createReportResponseMessage(String)} once a better test exists.
- */
-public class Listener implements MessageListener
-{
- private static Logger log = Logger.getLogger(Listener.class);
-
- public static final String CONTROL_TOPIC = "topic_control";
- public static final String RESPONSE_QUEUE = "response";
-
- private final Topic _topic;
- //private final Topic _control;
-
- private final Queue _response;
-
- /** Holds the connection to listen on. */
- private final Connection _connection;
-
- /** Holds the producer to send control messages on. */
- private final MessageProducer _controller;
-
- /** Holds the JMS session. */
- private final javax.jms.Session _session;
-
- /** Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. */
- private boolean init;
-
- /** Holds the count of messages received by this listener. */
- private int count;
-
- /** Used to hold the start time of the first message. */
- private long start;
- private static String clientId;
-
- Listener(Connection connection, int ackMode, String name) throws Exception
- {
- log.debug("Listener(Connection connection = " + connection + ", int ackMode = " + ackMode + ", String name = " + name
- + "): called");
-
- _connection = connection;
- _session = connection.createSession(false, ackMode);
-
- if (_session instanceof AMQSession)
- {
- _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, CONTROL_TOPIC);
- //_control = new AMQTopic(CONTROL_TOPIC);
- _response = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, RESPONSE_QUEUE);
- }
- else
- {
- _topic = _session.createTopic(CONTROL_TOPIC);
- //_control = _session.createTopic(CONTROL_TOPIC);
- _response = _session.createQueue(RESPONSE_QUEUE);
- }
-
- //register for events
- if (name == null)
- {
- log.debug("Calling _factory.createTopicConsumer().setMessageListener(this)");
- createTopicConsumer().setMessageListener(this);
- }
- else
- {
- log.debug("Calling createDurableTopicConsumer(name).setMessageListener(this)");
- createDurableTopicConsumer(name).setMessageListener(this);
- }
-
- _connection.start();
-
- _controller = createControlPublisher();
- System.out.println("Waiting for messages " + Config.getAckModeDescription(ackMode)
- +
- ((name == null)
- ? "" : (" (subscribed with name " + name + " and client id " + connection.getClientID() + ")"))
- + "...");
- }
-
- public static void main(String[] argv) throws Exception
- {
- clientId = "Listener-" + System.currentTimeMillis();
-
- NDC.push(clientId);
-
- Config config = new Config();
- config.setOptions(argv);
-
- //Connection con = config.createConnection();
- Connection con =
- new AMQConnection("amqp://guest:guest@testid/test?brokerlist='" + config.getHost() + ":" + config.getPort()
- + "'");
-
- if (config.getClientId() != null)
- {
- con.setClientID(config.getClientId());
- }
-
- new Listener(con, config.getAckMode(), config.getSubscriptionId());
-
- NDC.pop();
- NDC.remove();
- }
-
- /**
- * Checks whether or not a text field on a message has the specified value.
- *
- * @param m The message to check.
- * @param fieldName The name of the field to check.
- * @param value The expected value of the field to compare with.
- *
- * @return <tt>true</tt>If the specified field has the specified value, <tt>fals</tt> otherwise.
- *
- * @throws JMSException Any JMSExceptions are allowed to fall through.
- */
- private static boolean checkTextField(Message m, String fieldName, String value) throws JMSException
- {
- log.debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName
- + ", String value = " + value + "): called");
-
- String comp = m.getStringProperty(fieldName);
- log.debug("comp = " + comp);
-
- boolean result = (comp != null) && comp.equals(value);
- log.debug("result = " + result);
-
- return result;
- }
-
- public void onMessage(Message message)
- {
- NDC.push(clientId);
-
- log.debug("public void onMessage(Message message = " + message + "): called");
-
- if (!init)
- {
- start = System.nanoTime() / 1000000;
- count = 0;
- init = true;
- }
-
- try
- {
- if (isShutdown(message))
- {
- log.debug("Got a shutdown message.");
- shutdown();
- }
- else if (isReport(message))
- {
- log.debug("Got a report request message.");
-
- // Send the report.
- report();
- init = false;
- }
- }
- catch (JMSException e)
- {
- log.warn("There was a JMSException during onMessage.", e);
- }
- finally
- {
- NDC.pop();
- }
- }
-
- Message createReportResponseMessage(String msg) throws JMSException
- {
- Message message = _session.createTextMessage(msg);
-
- // Shove some more field table type in the message just to see if the other end can handle it.
- message.setBooleanProperty("BOOLEAN", true);
- message.setByteProperty("BYTE", (byte) 5);
- message.setDoubleProperty("DOUBLE", Math.PI);
- message.setFloatProperty("FLOAT", 1.0f);
- message.setIntProperty("INT", 1);
- message.setShortProperty("SHORT", (short) 1);
- message.setLongProperty("LONG", (long) 1827361278);
- message.setStringProperty("STRING", "hello");
-
- return message;
- }
-
- boolean isShutdown(Message m) throws JMSException
- {
- boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST");
-
- //log.debug("isShutdown = " + result);
-
- return result;
- }
-
- boolean isReport(Message m) throws JMSException
- {
- boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST");
-
- //log.debug("isReport = " + result);
-
- return result;
- }
-
- MessageConsumer createTopicConsumer() throws Exception
- {
- return _session.createConsumer(_topic);
- }
-
- MessageConsumer createDurableTopicConsumer(String name) throws Exception
- {
- return _session.createDurableSubscriber(_topic, name);
- }
-
- MessageProducer createControlPublisher() throws Exception
- {
- return _session.createProducer(_response);
- }
-
- private void shutdown()
- {
- try
- {
- _session.close();
- _connection.stop();
- _connection.close();
- }
- catch (Exception e)
- {
- e.printStackTrace(System.out);
- }
- }
-
- private void report()
- {
- log.debug("private void report(): called");
-
- try
- {
- String msg = getReport();
- _controller.send(createReportResponseMessage(msg));
- log.debug("Sent report: " + msg);
- }
- catch (Exception e)
- {
- e.printStackTrace(System.out);
- }
- }
-
- private String getReport()
- {
- long time = ((System.nanoTime() / 1000000) - start);
-
- return "Received " + count + " in " + time + "ms";
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java
deleted file mode 100644
index 4efdc1cb56..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.topic;
-
-import javax.jms.*;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.exchange.ExchangeDefaults;
-
-/**
- */
-class MessageFactory
-{
- private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray();
-
- private final Session _session;
- private final Topic _topic;
- private final Topic _control;
- private final byte[] _payload;
-
- MessageFactory(Session session) throws JMSException
- {
- this(session, 256);
- }
-
- MessageFactory(Session session, int size) throws JMSException
- {
- _session = session;
- if (session instanceof AMQSession)
- {
- _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topic_control");
- _control = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topictest.control");
- }
- else
- {
- _topic = session.createTopic("topic_control");
- _control = session.createTopic("topictest.control");
- }
-
- _payload = new byte[size];
-
- for (int i = 0; i < size; i++)
- {
- _payload[i] = (byte) DATA[i % DATA.length];
- }
- }
-
- private static boolean checkText(Message m, String s)
- {
- try
- {
- return (m instanceof TextMessage) && ((TextMessage) m).getText().equals(s);
- }
- catch (JMSException e)
- {
- e.printStackTrace(System.out);
-
- return false;
- }
- }
-
- Topic getTopic()
- {
- return _topic;
- }
-
- Message createEventMessage() throws JMSException
- {
- BytesMessage msg = _session.createBytesMessage();
- msg.writeBytes(_payload);
-
- return msg;
- }
-
- Message createShutdownMessage() throws JMSException
- {
- return _session.createTextMessage("SHUTDOWN");
- }
-
- Message createReportRequestMessage() throws JMSException
- {
- return _session.createTextMessage("REPORT");
- }
-
- Message createReportResponseMessage(String msg) throws JMSException
- {
- return _session.createTextMessage(msg);
- }
-
- boolean isShutdown(Message m)
- {
- return checkText(m, "SHUTDOWN");
- }
-
- boolean isReport(Message m)
- {
- return checkText(m, "REPORT");
- }
-
- Object getReport(Message m)
- {
- try
- {
- return ((TextMessage) m).getText();
- }
- catch (JMSException e)
- {
- e.printStackTrace(System.out);
-
- return e.toString();
- }
- }
-
- MessageConsumer createTopicConsumer() throws Exception
- {
- return _session.createConsumer(_topic);
- }
-
- MessageConsumer createDurableTopicConsumer(String name) throws Exception
- {
- return _session.createDurableSubscriber(_topic, name);
- }
-
- MessageConsumer createControlConsumer() throws Exception
- {
- return _session.createConsumer(_control);
- }
-
- MessageProducer createTopicPublisher() throws Exception
- {
- return _session.createProducer(_topic);
- }
-
- MessageProducer createControlPublisher() throws Exception
- {
- return _session.createProducer(_control);
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java b/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java
deleted file mode 100644
index c3b19b558a..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.topic;
-
-import javax.jms.*;
-
-public class Publisher implements MessageListener
-{
- private final Object _lock = new Object();
- private final Connection _connection;
- private final Session _session;
- private final MessageFactory _factory;
- private final MessageProducer _publisher;
- private int _count;
-
- Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception
- {
- _connection = connection;
- _session = _connection.createSession(false, ackMode);
- _factory = new MessageFactory(_session, size);
- _publisher = _factory.createTopicPublisher();
- _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
- System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + ".");
- }
-
- private void test(Config config) throws Exception
- {
- test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup());
- }
-
- private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception
- {
- _factory.createControlConsumer().setMessageListener(this);
- _connection.start();
-
- if (warmup > 0)
- {
- System.out.println("Runing warmup (" + warmup + " msgs)");
- long time = batch(warmup, consumerCount);
- System.out.println("Warmup completed in " + time + "ms");
- }
-
- long[] times = new long[batches];
- for (int i = 0; i < batches; i++)
- {
- if (i > 0)
- {
- Thread.sleep(delay * 1000);
- }
- times[i] = batch(msgCount, consumerCount);
- System.out.println("Batch " + (i + 1) + " of " + batches + " completed in " + times[i] + " ms.");
- }
-
- long min = min(times);
- long max = max(times);
- System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max));
-
- //request shutdown
- _publisher.send(_factory.createShutdownMessage());
-
- _connection.stop();
- _connection.close();
- }
-
- private long batch(int msgCount, int consumerCount) throws Exception
- {
- _count = consumerCount;
- long start = System.currentTimeMillis();
- publish(msgCount);
- waitForCompletion(consumerCount);
- return System.currentTimeMillis() - start;
- }
-
- private void publish(int count) throws Exception
- {
-
- //send events
- for (int i = 0; i < count; i++)
- {
- _publisher.send(_factory.createEventMessage());
- if ((i + 1) % 100 == 0)
- {
- System.out.println("Sent " + (i + 1) + " messages");
- }
- }
-
- //request report
- _publisher.send(_factory.createReportRequestMessage());
- }
-
- private void waitForCompletion(int consumers) throws Exception
- {
- System.out.println("Waiting for completion...");
- synchronized (_lock)
- {
- while (_count > 0)
- {
- _lock.wait();
- }
- }
- }
-
-
- public void onMessage(Message message)
- {
- System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining");
- if (_count == 0)
- {
- synchronized (_lock)
- {
- _lock.notify();
- }
- }
- }
-
- static long min(long[] times)
- {
- long min = times.length > 0 ? times[0] : 0;
- for (int i = 0; i < times.length; i++)
- {
- min = Math.min(min, times[i]);
- }
- return min;
- }
-
- static long max(long[] times)
- {
- long max = times.length > 0 ? times[0] : 0;
- for (int i = 0; i < times.length; i++)
- {
- max = Math.max(max, times[i]);
- }
- return max;
- }
-
- static long avg(long[] times, long min, long max)
- {
- long sum = 0;
- for (int i = 0; i < times.length; i++)
- {
- sum += times[i];
- }
-
- int adjustment = 0;
-
- // Remove min and max if we have run enough batches.
- if (times.length > 2)
- {
- sum -= min;
- sum -= max;
- adjustment = 2;
- }
-
- return (sum / (times.length - adjustment));
- }
-
- public static void main(String[] argv) throws Exception
- {
- Config config = new Config();
- config.setOptions(argv);
-
- Connection con = config.createConnection();
- int size = config.getPayload();
- int ackMode = config.getAckMode();
- boolean persistent = config.usePersistentMessages();
- new Publisher(con, size, ackMode, persistent).test(config);
- }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java b/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java
deleted file mode 100644
index 1d6ec07bb0..0000000000
--- a/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.topic;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import javax.jms.BytesMessage;
-import javax.jms.DeliveryMode;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.Session;
-import javax.jms.Topic;
-import javax.jms.TopicConnection;
-import javax.jms.TopicPublisher;
-import javax.jms.TopicSession;
-import javax.jms.TopicSubscriber;
-import javax.naming.NamingException;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.test.utils.QpidBrokerTestCase;
-
-public class TopicWithSelectorsTransientVolumeTest extends QpidBrokerTestCase
-{
- private static final int NUM_MSG_PER_ITERATION = 50;//must be a multiple of 10
- private static final int NUM_ITERATIONS = 1000;
-
- private static final int NUM_CONSUMERS = 50;
- private static final int MSG_SIZE = 1024;
- private static final byte[] BYTE_ARRAY = new byte[MSG_SIZE];
-
- private ArrayList<MyMessageSubscriber> _subscribers = new ArrayList<MyMessageSubscriber>();
- private HashMap<String,Long> _queueMsgCounts = new HashMap<String,Long>();
-
- private final static Object _lock=new Object();
- private boolean _producerFailed;
- private static int _finishedCount;
- private static int _failedCount;
-
- protected void setUp() throws Exception
- {
- super.setUp();
- init();
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
- private void init()
- {
- _finishedCount = 0;
- _failedCount = 0;
- _producerFailed = false;
- _subscribers.clear();
- _queueMsgCounts.clear();
- }
-
-
- private Message createMessage(Session session) throws JMSException
- {
- BytesMessage message = session.createBytesMessage();
- message.writeBytes(BYTE_ARRAY);
-
- return message;
- }
-
- /**
- * 1 Topic with 50 subscribers using a selector, and 1 producer sending 50,000 1K messages with 90% selector success ratio.
- */
- public void test50SubscribersWith90PercentMatched() throws Exception
- {
- Topic topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "test50ConsumersWith10PercentUnmatched");
-
- System.out.println("Creating consumers");
-
- MyMessageSubscriber sub;
-
- for(int i=1; i <= NUM_CONSUMERS; i++)
- {
- sub = new MyMessageSubscriber(topic, "consumer" + i, ((9 * NUM_MSG_PER_ITERATION * NUM_ITERATIONS) / 10));
- _subscribers.add(sub);
- }
-
- System.out.println("Starting consumers");
- for(MyMessageSubscriber s: _subscribers)
- {
- Thread consumer = new Thread(s);
- consumer.start();
- }
-
- System.out.println("Creating producer");
- MyMessageProducer prod = new MyMessageProducer(topic);
-
- long startTime = System.currentTimeMillis();
-
- System.out.println("Starting producer");
- Thread producer = new Thread(prod);
- producer.start();
-
-
- // Wait for all the messageConsumers to have finished or failed
- synchronized (_lock)
- {
- while (_finishedCount + _failedCount < NUM_CONSUMERS)
- {
- try
- {
- _lock.wait();
- }
- catch (InterruptedException e)
- {
- //ignore
- }
- }
- }
-
- long endTime = System.currentTimeMillis();
- System.out.println("Elapsed time for messaging: " + (endTime-startTime) + "ms");
-
- assertFalse("Producer failed to send all messages", _producerFailed);
-
- //check if all messages received by consumers, or if there were failures
- if (_finishedCount != NUM_CONSUMERS)
- {
- fail(_failedCount + " consumers did not recieve all their expected messages");
- }
-
- //check if all queue depths were 0
- for(String consumer: _queueMsgCounts.keySet())
- {
- long depth = _queueMsgCounts.get(consumer);
- assertEquals(consumer + " subscription queue msg count was not 0", 0, depth);
- }
-
- }
-
- private class MyMessageProducer implements Runnable
- {
- private TopicConnection _connection;
- private TopicSession _session;
- private TopicPublisher _messagePublisher;
-
- public MyMessageProducer(Topic topic) throws JMSException, NamingException
- {
- _connection = (TopicConnection) getConnection();
- _session = (TopicSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _messagePublisher = _session.createPublisher(topic);
- }
-
- public void run()
- {
- try
- {
- for(int iter = 0; iter < NUM_ITERATIONS; iter++)
- {
- int i = 0;
-
- //send 90% matching messages
- for (; i < (9 * NUM_MSG_PER_ITERATION)/10; i++)
- {
- Message message = createMessage(_session);
- message.setStringProperty("testprop", "true");
-
- _messagePublisher.publish(message, DeliveryMode.NON_PERSISTENT,
- Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
-
- Thread.yield();
- }
-
- //send remaining 10% non-matching messages
- for (; i < NUM_MSG_PER_ITERATION; i++)
- {
- Message message = _session.createMessage();
- message.setStringProperty("testprop", "false");
-
- _messagePublisher.publish(message, DeliveryMode.NON_PERSISTENT,
- Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
-
- Thread.yield();
- }
- }
-
- }
- catch (Exception exp)
- {
- System.out.println("producer: caught an exception, probably exiting before all messages sent");
- exp.printStackTrace();
- synchronized (_lock)
- {
- _producerFailed=true;
- _lock.notifyAll();
- }
- }
- }
- }
-
-
- private class MyMessageSubscriber implements Runnable
- {
- /* The topic this subscriber is subscribing to */
- private Topic _topic;
- private String _consumerName;
- private int _outstandingMsgCount;
- private TopicConnection _connection;
- private TopicSession _session;
- private TopicSubscriber _durSub;
-
- public MyMessageSubscriber(Topic topic, String consumerName, int messageCount) throws JMSException, NamingException
- {
- _outstandingMsgCount = messageCount;
- _topic=topic;
- _consumerName = consumerName;
- _connection = (TopicConnection) getConnection();
- _session = (TopicSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _durSub = _session.createDurableSubscriber(_topic, _consumerName,"testprop='true'", false);
- _connection.start();
- }
-
- public void run()
- {
-
- boolean failed = false;
- do
- {
- Message m = null;
- try
- {
- m = _durSub.receive(10000);
- }
- catch (JMSException exp)
- {
- System.out.println(_consumerName + ": caught an exception handling a received message");
- exp.printStackTrace();
-
- failed = true;
- break;
- }
-
- Thread.yield();
-
- _outstandingMsgCount--;
-
- if(_outstandingMsgCount % 500 == 0)
- {
- System.out.println(_consumerName + ": outstanding message count: " + _outstandingMsgCount);
- }
-
- if(m == null)
- {
- if(_outstandingMsgCount != 0)
- {
- failed = true;
- }
- break;
- }
- }
- while(_outstandingMsgCount > 0);
-
- System.out.println(_consumerName + ": outstanding message count: " + _outstandingMsgCount);
-
- try
- {
- AMQQueue subcriptionQueue = new AMQQueue(ExchangeDefaults.TOPIC_EXCHANGE_NAME,"clientid" + ":" + _consumerName);
-
- ((AMQSession)_session).sync();
- Long depth = ((AMQSession)_session).getQueueDepth(subcriptionQueue);
- _queueMsgCounts.put(_consumerName, depth);
-
- System.out.println(_consumerName + ": completion queue msg count: " + depth);
- }
- catch (AMQException exp)
- {
- System.out.println(_consumerName + ": caught an exception determining completion queue depth");
- exp.printStackTrace();
- }
- finally
- {
- try
- {
- _session.unsubscribe(_consumerName);
- }
- catch (JMSException e)
- {
- System.out.println(_consumerName + ": caught an exception whilst unsubscribing");
- e.printStackTrace();
- }
- }
-
- synchronized (_lock)
- {
- if (_outstandingMsgCount == 0 && !failed)
- {
- _finishedCount++;
- System.out.println(_consumerName + ": finished");
- }
- else
- {
- _failedCount++;
- System.out.println(_consumerName + ": failed");
- }
- _lock.notifyAll();
- }
-
- }
- }
-
- //helper method to allow easily running against an external standalone broker
-// public static void main(String[] args) throws Exception
-// {
-// System.setProperty("broker.config", "/dev/null");
-// System.setProperty("broker", "external");
-// System.setProperty("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory");
-// System.setProperty("java.naming.provider.url", "test-profiles/test-provider.properties");
-//
-// TopicWithSelectorsTransientVolumeTest test = new TopicWithSelectorsTransientVolumeTest();
-// test.init();
-// test.test50SubscribersWith90PercentMatched();
-// test.tearDown();
-// }
-}
diff --git a/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties b/java/perftests/src/main/resources/perftests.properties
index 1f572af58a..d8823f9dc5 100644
--- a/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties
+++ b/java/perftests/src/main/resources/perftests.properties
@@ -1,4 +1,3 @@
-#
# 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
@@ -15,10 +14,7 @@
# 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
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
-# register some connection factories
-# connectionfactory.[jndiname] = [ConnectionURL]
-connectionfactory.default = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' \ No newline at end of file
+connectionfactory.connectionfactory = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'
diff --git a/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/ArgumentParserTest.java
new file mode 100644
index 0000000000..3be82627fe
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java b/java/perftests/src/test/java/org/apache/qpid/disttest/ConfigFileHelper.java
new file mode 100644
index 0000000000..12ba3b56ad
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/VisitorTest.java
new file mode 100644
index 0000000000..320e7d8c9d
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientCommandVisitorTest.java
new file mode 100644
index 0000000000..4a82f6719f
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ClientTest.java
new file mode 100644
index 0000000000..198baa6ef4
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java
new file mode 100644
index 0000000000..ff7cfd2b41
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ConsumerParticipantTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.assertExpectedConsumerResults;
+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 javax.jms.Session;
+
+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);
+ when(_delegate.getAcknowledgeMode(SESSION_NAME1)).thenReturn(Session.CLIENT_ACKNOWLEDGE);
+
+ _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);
+
+ assertExpectedConsumerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.CLIENT_ACKNOWLEDGE, null, 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);
+
+ assertExpectedConsumerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.CLIENT_ACKNOWLEDGE, null, 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;
+ final int batchSize = 3;
+ long totalPayloadSize = PAYLOAD_SIZE_PER_MESSAGE * numberOfMessages;
+ _command.setNumberOfMessages(numberOfMessages);
+ _command.setBatchSize(batchSize);
+
+ ParticipantResult result = _consumerParticipant.doIt(CLIENT_NAME);
+
+ assertExpectedConsumerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.CLIENT_ACKNOWLEDGE, batchSize, 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;
+ assertExpectedConsumerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.CLIENT_ACKNOWLEDGE, null, 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/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/MessageProviderTest.java
new file mode 100644
index 0000000000..ffc3733eb7
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantExecutorTest.java
new file mode 100644
index 0000000000..f30e4664ff
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantRegistryTest.java
new file mode 100644
index 0000000000..bd0d5a39c8
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.java
new file mode 100644
index 0000000000..3b21834a5c
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantResultFactoryTest.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 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);
+
+ int totalNumberOfConsumers = 0;
+ int totalNumberOfProducers = 1;
+
+ int acknowledgeMode = 1;
+
+ ProducerParticipantResult result = _participantResultFactory.createForProducer(PARTICIPANT_NAME,
+ REGISTERED_CLIENT_NAME,
+ command,
+ acknowledgeMode,
+ NUMBER_OF_MESSAGES_PROCESSED,
+ PAYLOAD_SIZE,
+ TOTAL_PAYLOAD_PROCESSED,
+ START, END);
+
+ assertCommonResultProperties(result);
+
+ assertEquals(deliveryMode, result.getDeliveryMode());
+ assertEquals(acknowledgeMode, result.getAcknowledgeMode());
+ assertEquals(priority, result.getPriority());
+ assertEquals(producerInterval, result.getInterval());
+ assertEquals(producerStartDelay, result.getStartDelay());
+ assertEquals(timeToLive, result.getTimeToLive());
+ assertEquals(totalNumberOfConsumers, result.getTotalNumberOfConsumers());
+ assertEquals(totalNumberOfProducers, result.getTotalNumberOfProducers());
+ }
+
+ 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);
+
+ int totalNumberOfConsumers = 1;
+ int totalNumberOfProducers = 0;
+
+ int acknowledgeMode = 2;
+
+ ConsumerParticipantResult result = _participantResultFactory.createForConsumer(PARTICIPANT_NAME,
+ REGISTERED_CLIENT_NAME,
+ command,
+ acknowledgeMode,
+ 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());
+ assertEquals(totalNumberOfConsumers, result.getTotalNumberOfConsumers());
+ assertEquals(totalNumberOfProducers, result.getTotalNumberOfProducers());
+ }
+
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java
new file mode 100644
index 0000000000..a013cb0a06
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ParticipantTestHelper.java
@@ -0,0 +1,83 @@
+/*
+ * 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 assertExpectedConsumerResults(ParticipantResult result, String participantName, String registeredClientName, long expectedTestStartTime, int expectedAcknowledgeMode, Integer expectedBatchSize, Integer expectedNumberOfMessages, Integer expectedPayloadSize, Long expectedTotalPayloadProcessed, Long expectedMinimumExpectedDuration)
+ {
+ assertExpectedResults(result, participantName, registeredClientName, expectedTestStartTime,
+ expectedAcknowledgeMode, expectedBatchSize, expectedNumberOfMessages, expectedPayloadSize, expectedTotalPayloadProcessed, expectedMinimumExpectedDuration);
+ assertEquals("Unexpected number of consumers", 1, result.getTotalNumberOfConsumers());
+ assertEquals("Unexpected number of producers", 0, result.getTotalNumberOfProducers());
+ }
+
+ public static void assertExpectedProducerResults(ParticipantResult result, String participantName, String registeredClientName, long expectedTestStartTime, int expectedAcknowledgeMode, Integer expectedBatchSize, Integer expectedNumberOfMessages, Integer expectedPayloadSize, Long expectedTotalPayloadProcessed, Long expectedMinimumExpectedDuration)
+ {
+ assertExpectedResults(result, participantName, registeredClientName, expectedTestStartTime, expectedAcknowledgeMode, expectedBatchSize, expectedNumberOfMessages, expectedPayloadSize, expectedTotalPayloadProcessed, expectedMinimumExpectedDuration);
+ assertEquals("Unexpected number of producers", 1, result.getTotalNumberOfProducers());
+ assertEquals("Unexpected number of consumers", 0, result.getTotalNumberOfConsumers());
+ }
+
+ private static void assertExpectedResults(ParticipantResult result, String participantName, String registeredClientName, long expectedTestStartTime, int expectedAcknowledgeMode, Integer expectedBatchSize, 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());
+
+ assertEquals("unexpected acknowledge mode", expectedAcknowledgeMode, result.getAcknowledgeMode());
+
+ if(expectedNumberOfMessages != null)
+ {
+ assertEquals("unexpected number of messages", expectedNumberOfMessages.intValue(), result.getNumberOfMessagesProcessed());
+ }
+ if(expectedBatchSize != null)
+ {
+ assertEquals("unexpected batch size", expectedBatchSize.intValue(), result.getBatchSize());
+ }
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java
new file mode 100644
index 0000000000..cf05623e8f
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/client/ProducerParticipantTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.assertExpectedProducerResults;
+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 javax.jms.Session;
+
+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);
+ when(_delegate.getAcknowledgeMode(SESSION_NAME1)).thenReturn(Session.AUTO_ACKNOWLEDGE);
+
+ _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;
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, expectedPublishedStartTime, Session.AUTO_ACKNOWLEDGE, null, 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);
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.AUTO_ACKNOWLEDGE, null, 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);
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.AUTO_ACKNOWLEDGE, null, 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 batchSize = 3;
+ 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(batchSize);
+
+ ParticipantResult result = _producer.doIt(CLIENT_NAME);
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.AUTO_ACKNOWLEDGE, batchSize, 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);
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.AUTO_ACKNOWLEDGE, null, 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;
+ assertExpectedProducerResults(result, PARTICIPANT_NAME1, CLIENT_NAME, _testStartTime,
+ Session.AUTO_ACKNOWLEDGE, null, 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/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/ListPropertyValueTest.java
new file mode 100644
index 0000000000..75a634ba54
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/PropertyValueFactoryTest.java
new file mode 100644
index 0000000000..2d560163c2
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RandomPropertyValueTest.java
new file mode 100644
index 0000000000..bd5de3e370
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/RangePropertyValueTest.java
new file mode 100644
index 0000000000..91791c9d55
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/client/property/SimplePropertyValueTest.java
new file mode 100644
index 0000000000..a347d866c7
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java
new file mode 100644
index 0000000000..cc969e1ef2
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ClientRegistryTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.Timer;
+import java.util.TimerTask;
+
+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 static final String CLIENT2_REGISTERED_NAME = "CLIENT2_REGISTERED_NAME";
+ private static final int AWAIT_DELAY = 100;
+
+ 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
+ }
+ }
+
+ public void testAwaitOneClientWhenClientNotRegistered()
+ {
+ int numberOfClientsAbsent = _clientRegistry.awaitClients(1, AWAIT_DELAY);
+ assertEquals(1, numberOfClientsAbsent);
+ }
+
+ public void testAwaitOneClientWhenClientAlreadyRegistered()
+ {
+ _clientRegistry.registerClient(CLIENT1_REGISTERED_NAME);
+
+ int numberOfClientsAbsent = _clientRegistry.awaitClients(1, AWAIT_DELAY);
+ assertEquals(0, numberOfClientsAbsent);
+ }
+
+ public void testAwaitTwoClientWhenClientRegistersWhilstWaiting()
+ {
+ _clientRegistry.registerClient(CLIENT1_REGISTERED_NAME);
+ registerClientLater(CLIENT2_REGISTERED_NAME, 50);
+
+ int numberOfClientsAbsent = _clientRegistry.awaitClients(2, AWAIT_DELAY);
+ assertEquals(0, numberOfClientsAbsent);
+ }
+
+ private void registerClientLater(final String clientName, long delayInMillis)
+ {
+ doLater(new TimerTask()
+ {
+ @Override
+ public void run()
+ {
+ _clientRegistry.registerClient(clientName);
+ }
+ }, delayInMillis);
+ }
+
+ private void doLater(TimerTask task, long delayInMillis)
+ {
+ Timer timer = new Timer();
+ timer.schedule(task, delayInMillis);
+ }
+}
diff --git a/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java
new file mode 100644
index 0000000000..bc58ea41c5
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ControllerTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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 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 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 testControllerReceivesTwoExpectedClientRegistrations()
+ {
+ Config configWithTwoClients = createMockConfig(2);
+ _controller.setConfig(configWithTwoClients);
+ when(_clientRegistry.awaitClients(2, REGISTRATION_TIMEOUT)).thenReturn(0);
+
+ _controller.awaitClientRegistrations();
+ }
+
+ public void testControllerDoesntReceiveAnyRegistrations()
+ {
+ when(_clientRegistry.awaitClients(1, REGISTRATION_TIMEOUT)).thenReturn(1);
+
+ 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 Config createMockConfig(int numberOfClients)
+ {
+ Config config = mock(Config.class);
+ when(config.getTotalNumberOfClients()).thenReturn(numberOfClients);
+ return config;
+ }
+
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/ParticipatingClientsTest.java
new file mode 100644
index 0000000000..284db38f44
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.java
new file mode 100644
index 0000000000..983da299b9
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/TestRunnerTest.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.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 String PARTICIPANT_NAME = "TEST_PARTICIPANT_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(PARTICIPANT_NAME);
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ClientConfigTest.java
new file mode 100644
index 0000000000..d4af439dea
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigReaderTest.java
new file mode 100644
index 0000000000..af9ec28db0
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTest.java
new file mode 100644
index 0000000000..88750b9737
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConfigTestUtils.java
new file mode 100644
index 0000000000..ce5f92724f
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConnectionConfigTest.java
new file mode 100644
index 0000000000..7c839ed462
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ConsumerConfigTest.java
new file mode 100644
index 0000000000..c011ff4711
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/IterationValueTest.java
new file mode 100644
index 0000000000..7998eae37e
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/MessageProviderConfigTest.java
new file mode 100644
index 0000000000..a3b367a4b4
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/ProducerConfigTest.java
new file mode 100644
index 0000000000..b9e591f113
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/SessionConfigTest.java
new file mode 100644
index 0000000000..8775e4064d
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestConfigTest.java
new file mode 100644
index 0000000000..1212a57606
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/TestInstanceTest.java
new file mode 100644
index 0000000000..928fbe58cf
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json b/java/perftests/src/test/java/org/apache/qpid/disttest/controller/config/sampleConfig.json
new file mode 100644
index 0000000000..9e1168129b
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/jms/JmsMessageAdaptorTest.java
new file mode 100644
index 0000000000..ab0f52263b
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/message/JsonHandlerTest.java
new file mode 100644
index 0000000000..4a56fff8fe
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java
new file mode 100644
index 0000000000..12731c06f4
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/message/ParticipantResultTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.*;
+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;
+
+ int totalNumberOfConsumers = 1;
+ int totalNumberOfProducers = 1;
+
+ int acknowledgeMode = 1;
+
+ result.setParticipantName(participantName);
+ result.setTestName(testName);
+ result.setIterationNumber(iterationNumber);
+ result.setConfiguredClientName(clientConfiguredName);
+
+ result.setAcknowledgeMode(acknowledgeMode);
+ result.setNumberOfMessagesProcessed(numberOfMessages);
+ result.setConfiguredClientName(clientConfiguredName);
+ result.setBatchSize(batchSize);
+
+ result.setStartDate(new Date(startTime));
+ result.setEndDate(new Date(endTime));
+ result.setMaximumDuration(maximumDuration);
+
+ result.setTotalNumberOfConsumers(totalNumberOfConsumers);
+ result.setTotalNumberOfProducers(totalNumberOfProducers);
+
+ result.setErrorMessage(errorMessage);
+
+ assertEquals(participantName, result.getAttributes().get(PARTICIPANT_NAME));
+ assertEquals(testName, result.getAttributes().get(TEST_NAME));
+ assertEquals(iterationNumber, result.getAttributes().get(ITERATION_NUMBER));
+ 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(timeTaken, result.getAttributes().get(TIME_TAKEN));
+ assertEquals(timeTaken, result.getAttributes().get(TIME_TAKEN));
+ assertEquals(batchSize, result.getAttributes().get(BATCH_SIZE));
+ assertEquals(maximumDuration, result.getAttributes().get(MAXIMUM_DURATION));
+ assertEquals(totalNumberOfConsumers, result.getAttributes().get(TOTAL_NUMBER_OF_CONSUMERS));
+ assertEquals(totalNumberOfProducers, result.getAttributes().get(TOTAL_NUMBER_OF_PRODUCERS));
+ assertEquals(acknowledgeMode, result.getAttributes().get(ACKNOWLEDGE_MODE));
+ assertEquals(errorMessage, result.getAttributes().get(ERROR_MESSAGE));
+ }
+
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/AggregatorTest.java
new file mode 100644
index 0000000000..393837b4d5
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java
new file mode 100644
index 0000000000..72743be1d1
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/ParticipantResultAggregatorTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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 javax.jms.Session;
+
+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());
+ }
+
+ public void testConstantBatchSizesRolledUp() throws Exception
+ {
+ final int batchSize = 10;
+
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setBatchSize(batchSize);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setBatchSize(batchSize);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(batchSize, aggregratedResult.getBatchSize());
+ }
+
+ public void testDifferingBatchSizesNotRolledUp() throws Exception
+ {
+ final int batch1Size = 10;
+ final int batch2Size = 20;
+
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setBatchSize(batch1Size);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setBatchSize(batch2Size);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(0, aggregratedResult.getBatchSize());
+ }
+
+ public void testConstantAcknowledgeModesRolledUp() throws Exception
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setAcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setAcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(Session.DUPS_OK_ACKNOWLEDGE, aggregratedResult.getAcknowledgeMode());
+ }
+
+ public void testDifferingAcknowledgeModesNotRolledUp() throws Exception
+ {
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setBatchSize(Session.AUTO_ACKNOWLEDGE);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setBatchSize(Session.SESSION_TRANSACTED);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(-1, aggregratedResult.getAcknowledgeMode());
+ }
+
+ public void testSumNumberOfConsumerAndProducers() throws Exception
+ {
+ final int expectedNumberOfProducers = 1;
+ final int expectedNumberOfConsumers = 2;
+
+ ParticipantResult result1 = new ParticipantResult();
+ result1.setTotalNumberOfConsumers(1);
+
+ ParticipantResult result2 = new ParticipantResult();
+ result2.setTotalNumberOfConsumers(1);
+
+ ParticipantResult result3 = new ParticipantResult();
+ result2.setTotalNumberOfProducers(1);
+
+ _aggregator.aggregate(result1);
+ _aggregator.aggregate(result2);
+ _aggregator.aggregate(result3);
+
+ ParticipantResult aggregratedResult = _aggregator.getAggregatedResult();
+ assertEquals(expectedNumberOfConsumers, aggregratedResult.getTotalNumberOfConsumers());
+ assertEquals(expectedNumberOfProducers, aggregratedResult.getTotalNumberOfProducers());
+ }
+
+}
diff --git a/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java
new file mode 100644
index 0000000000..a803120cc6
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/results/aggregation/TestResultAggregatorTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 static final int BATCH_SIZE = 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.getAllConsumerParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ BATCH_SIZE, NUMBER_OF_MESSAGES_CONSUMED_IN_TOTAL, 2, 0);
+
+ assertMinimalAggregatedResults(
+ aggregatedTestResult.getAllProducerParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ BATCH_SIZE, NUMBER_OF_MESSAGES_PRODUCED, 0, 1);
+
+ assertMinimalAggregatedResults(
+ aggregatedTestResult.getAllParticipantResult(),
+ TEST1_NAME, TEST1_ITERATION_NUMBER,
+ BATCH_SIZE, NUMBER_OF_MESSAGES_CONSUMED_IN_TOTAL, 2, 1);
+ }
+
+ 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, int expectedBatchSize, long expectedNumberOfMessagesProcessed, int expectedTotalNumberOfConsumers, int expectedTotalNumberOfProducers)
+ {
+ assertEquals("Unexpected test name in " + result.getParticipantName(), expectedTestName, result.getTestName());
+ assertEquals("Unexpected iteration number in " + result.getParticipantName(), expectedIterationNumber, result.getIterationNumber());
+ assertEquals("Unexpected batch size " + result.getParticipantName(), expectedBatchSize, result.getBatchSize());
+ assertEquals("Unexpected number of messages processed in " + result.getParticipantName(), expectedNumberOfMessagesProcessed, result.getNumberOfMessagesProcessed());
+ assertEquals("Unexpected total number of consumers " + result.getParticipantName(), expectedTotalNumberOfConsumers, result.getTotalNumberOfConsumers());
+ assertEquals("Unexpected total number of producers " + result.getParticipantName(), expectedTotalNumberOfProducers, result.getTotalNumberOfProducers());
+ }
+
+ 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, BATCH_SIZE, PAYLOAD_SIZE, TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER, CONSUMER1_STARTDATE, CONSUMER1_ENDDATE, 1, 0);
+ testResult.addParticipantResult(consumerResult1);
+
+ ConsumerParticipantResult consumerResult2 = new ConsumerParticipantResult();
+ setPropertiesOn(consumerResult2, TEST1_NAME, TEST1_ITERATION_NUMBER, CONSUMER_PARTICIPANT_NAME2, NUMBER_OF_MESSAGES_PROCESSED_PER_CONSUMER, BATCH_SIZE, PAYLOAD_SIZE, TOTAL_PAYLOAD_PROCESSED_PER_CONSUMER, CONSUMER2_STARTDATE, CONSUMER2_ENDDATE, 1, 0);
+ testResult.addParticipantResult(consumerResult2);
+
+ ParticipantResult producerResult = new ProducerParticipantResult();
+ setPropertiesOn(producerResult, TEST1_NAME, TEST1_ITERATION_NUMBER, PRODUCER_PARTICIPANT_NAME, NUMBER_OF_MESSAGES_PRODUCED, BATCH_SIZE, PAYLOAD_SIZE, TOTAL_PAYLOAD_PRODUCED_IN_TOTAL, PRODUCER_STARTDATE, PRODUCER_ENDDATE, 0, 1);
+ testResult.addParticipantResult(producerResult);
+
+ return testResult;
+ }
+
+ private void setPropertiesOn(ParticipantResult participantResult, String testName, int iterationNumber, String participantName, long numberOfMessagesProcessed, int batchSize, int payloadSize, long totalPayloadProcessed, long start, long end, int totalNumberOfConsumers, int totalNumberOfProducers)
+ {
+ participantResult.setParticipantName(participantName);
+ participantResult.setTestName(testName);
+ participantResult.setIterationNumber(iterationNumber);
+ participantResult.setTotalNumberOfConsumers(totalNumberOfConsumers);
+ participantResult.setTotalNumberOfProducers(totalNumberOfProducers);
+
+ participantResult.setNumberOfMessagesProcessed(numberOfMessagesProcessed);
+ participantResult.setPayloadSize(payloadSize);
+ participantResult.setTotalPayloadProcessed(totalPayloadProcessed);
+ participantResult.setStartDate(new Date(start));
+ participantResult.setEndDate(new Date(end));
+ participantResult.setBatchSize(batchSize);
+ }
+}
diff --git a/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.java
new file mode 100644
index 0000000000..088746d8cd
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVFormaterTest.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.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.*;
+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.NUMBER_OF_MESSAGES_PROCESSED;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PARTICIPANT_NAME;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.PAYLOAD_SIZE;
+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.THROUGHPUT;
+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.TOTAL_NUMBER_OF_CONSUMERS;
+import static org.apache.qpid.disttest.message.ParticipantAttribute.TOTAL_NUMBER_OF_PRODUCERS;
+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.qmf.QMFProperty.AccessCode;
+
+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);
+ when(participantResult.getParticipantName()).thenReturn(PARTICIPANT);
+
+ 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, 0);
+ participantAttributes.put(PAYLOAD_SIZE, 1);
+ participantAttributes.put(PRIORITY, 2);
+ participantAttributes.put(TIME_TO_LIVE, 3);
+ participantAttributes.put(ACKNOWLEDGE_MODE, 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_NUMBER_OF_CONSUMERS, 1);
+ participantAttributes.put(TOTAL_NUMBER_OF_PRODUCERS, 2);
+ 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/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java b/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/CSVOrderParticipantResultComparatorTest.java
new file mode 100644
index 0000000000..6cec4b5245
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv b/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv
new file mode 100644
index 0000000000..cfffb1e549
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/disttest/results/formatting/expectedOutput.csv
@@ -0,0 +1,2 @@
+testName,iterationNumber,clientName,participantName,numberOfMessages,payloadSizeB,priority,timeToLiveMs,acknowledgeMode,deliveryMode,batchSize,maximumDurationMs,producerStartDelayMs,producerIntervalMs,isTopic,isDurableSubscription,isBrowsingSubscription,isSelector,isNoLocal,isSynchronousConsumer,totalNumberOfConsumers,totalNumberOfProducers,totalPayloadProcessedB,throughputKbPerS,timeTakenMs,errorMessage
+TEST1,0,CONFIGURED_CLIENT1,PARTICIPANT,0,1,2,3,4,5,6,7,8,9,true,false,true,false,true,false,1,2,1024,2048,1000,error \ No newline at end of file
diff --git a/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java
new file mode 100644
index 0000000000..96daf64526
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java
new file mode 100644
index 0000000000..784e43469e
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.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 Session _session;
+ private List<QueueConfig> _configs;
+ private String _queueName;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ Connection 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(_session, _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(_session, _configs);
+
+ assertQueueBound(_queueName, true);
+ }
+
+ public void testDeleteQueues() throws Exception
+ {
+ _configs.add(new QueueConfig(_queueName, true, EMPTY_ATTRIBUTES));
+
+ assertQueueBound(_queueName, false);
+
+ _creator.createQueues(_session, _configs);
+ assertQueueBound(_queueName, true);
+
+ _creator.deleteQueues(_session, _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(_session, 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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java
new file mode 100644
index 0000000000..808b428bc9
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java
new file mode 100644
index 0000000000..d599bdc5c4
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java
new file mode 100644
index 0000000000..a3c0430865
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java
new file mode 100644
index 0000000000..7f0c23eb38
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java
new file mode 100644
index 0000000000..4a872a7ee2
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java
new file mode 100644
index 0000000000..dcbff6518b
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java
new file mode 100644
index 0000000000..54bb9efa98
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java
new file mode 100644
index 0000000000..9fd90d3215
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ControllerAndClientTest extends DistributedTestSystemTestBase
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAndClientTest.class);
+ private static final long CLIENT_BACKGROUND_THREAD_WAIT_TIME = 5000;
+
+ 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()
+ {
+ try
+ {
+ client.start();
+ client.waitUntilStopped(CLIENT_BACKGROUND_THREAD_WAIT_TIME);
+ }
+ finally
+ {
+ LOGGER.debug("Client thread {} finished", clientThreadName);
+ }
+ }
+ }, clientThreadName);
+ clientThread.start();
+ return clientThread;
+ }
+
+}
diff --git a/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json
new file mode 100644
index 0000000000..89123302b7
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json
new file mode 100644
index 0000000000..605e5cb585
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json
new file mode 100644
index 0000000000..8d210dce84
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json
new file mode 100644
index 0000000000..f94c4f0ae0
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json
new file mode 100644
index 0000000000..4abd7f4feb
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java
new file mode 100644
index 0000000000..ad7f0e0682
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json
new file mode 100644
index 0000000000..b49603ef23
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java
new file mode 100644
index 0000000000..63c9b42858
--- /dev/null
+++ b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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_DIR_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 csvOutputDir = createTemporaryCsvDirectory();
+ assertTrue("CSV output dir must not exist",csvOutputDir.isDirectory());
+
+ final String[] args = new String[] {TEST_CONFIG_PROP + "=" + TEST_CONFIG,
+ JNDI_CONFIG_PROP + "=" + JNDI_CONFIG_FILE,
+ OUTPUT_DIR_PROP + "=" + csvOutputDir.getAbsolutePath()};
+ _runner = new ControllerRunner();
+ _runner.parseArgumentsIntoConfig(args);
+ _runner.runController();
+
+ File expectedCsvOutputFile = new File(csvOutputDir, "endtoend.csv");
+ assertTrue("CSV output file must exist", expectedCsvOutputFile.exists());
+ final String csvContents = FileUtils.readFileAsString(expectedCsvOutputFile);
+ 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 createTemporaryCsvDirectory() throws IOException
+ {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ File csvDir = new File(tmpDir, "csv");
+ csvDir.mkdir();
+ csvDir.deleteOnExit();
+ return csvDir;
+ }
+
+}
diff --git a/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json
new file mode 100644
index 0000000000..1b7cc51265
--- /dev/null
+++ b/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/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties b/java/perftests/src/test/java/org/apache/qpid/systest/disttest/perftests.systests.properties
new file mode 100644
index 0000000000..b5d053227c
--- /dev/null
+++ b/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